Imported Upstream version 1.5
Jose Luis Rivero
10 years ago
0 | Makefile.in | |
1 | autom4te.cache/* | |
2 | aclocal.m4 | |
3 | config.guess | |
4 | config.sub | |
5 | configure | |
6 | depcomp | |
7 | install-sh | |
8 | ltmain.sh | |
9 | missing | |
10 | *~ | |
11 | src/gjk/config.h.in | |
12 | build/* | |
13 | ccd.pc |
0 | libccd | |
1 | ------- | |
2 | ||
3 | Copyright (c)2010-2012 Daniel Fiser <danfis@danfis.cz>, | |
4 | Intelligent and Mobile Robotics Group, Department of Cybernetics, | |
5 | Faculty of Electrical Engineering, Czech Technical University in Prague. | |
6 | All rights reserved. | |
7 | ||
8 | ||
9 | This work was supported by SYMBRION and REPLICATOR projects. | |
10 | The SYMBRION project is funded by European Commission within the work | |
11 | "Future and Emergent Technologies Proactive" under grant agreement no. | |
12 | 216342. | |
13 | The REPLICATOR project is funded within the work programme "Cognitive | |
14 | Systems, Interaction, Robotics" under grant agreement no. 216240. | |
15 | http://www.symbrion.eu/ | |
16 | http://www.replicators.eu/ | |
17 | ||
18 | ||
19 | Redistribution and use in source and binary forms, with or without | |
20 | modification, are permitted provided that the following conditions are met: | |
21 | ||
22 | - Redistributions of source code must retain the above copyright notice, | |
23 | this list of conditions and the following disclaimer. | |
24 | ||
25 | - Redistributions in binary form must reproduce the above copyright | |
26 | notice, this list of conditions and the following disclaimer in the | |
27 | documentation and/or other materials provided with the distribution. | |
28 | ||
29 | - Neither the name of the University nor the names of its contributors | |
30 | may be used to endorse or promote products derived from this software | |
31 | without specific prior written permission. | |
32 | ||
33 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
34 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
35 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
36 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
37 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
38 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
39 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
40 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
41 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
42 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
43 | POSSIBILITY OF SUCH DAMAGE. |
0 | cmake_minimum_required(VERSION 2.8) | |
1 | project(libccd C) | |
2 | ||
3 | set(CCD_VERSION "1.5") | |
4 | set(CCD_SOVERSION "2") | |
5 | set(PKG_DESC "Library for collision detection between convex shapes") | |
6 | set(LIB_SUFFIX "" CACHE STRING "Library installation directory suffix") | |
7 | ||
8 | include_directories("src/") | |
9 | ||
10 | # make sure only DOUBLE or SINGLE is set; default to SINGLE | |
11 | if (${CCD_SINGLE}) | |
12 | set(CCD_DOUBLE false) | |
13 | else() | |
14 | set(CCD_SINGLE true) | |
15 | endif() | |
16 | ||
17 | if (${CCD_DOUBLE}) | |
18 | set(CCD_SINGLE false) | |
19 | endif() | |
20 | ||
21 | # set the default build type | |
22 | if (NOT CMAKE_BUILD_TYPE) | |
23 | set(CMAKE_BUILD_TYPE Release) | |
24 | endif() | |
25 | ||
26 | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/ccd/config.h.cmake.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/ccd/config.h") | |
27 | ||
28 | if(NOT WIN32) | |
29 | find_library(MATH m) | |
30 | else() | |
31 | set(MATH "") | |
32 | endif() | |
33 | ||
34 | set(SOURCE_FILES | |
35 | src/ccd.c | |
36 | src/mpr.c | |
37 | src/polytope.c | |
38 | src/support.c | |
39 | src/vec3.c) | |
40 | ||
41 | add_library(ccd SHARED ${SOURCE_FILES}) | |
42 | set_target_properties(ccd PROPERTIES VERSION ${CCD_VERSION} SOVERSION ${CCD_SOVERSION}) | |
43 | ||
44 | target_link_libraries(ccd ${MATH}) | |
45 | ||
46 | add_library(ccd_static STATIC ${SOURCE_FILES}) | |
47 | set_target_properties(ccd_static PROPERTIES OUTPUT_NAME ccd) | |
48 | target_link_libraries(ccd_static ${MATH}) | |
49 | ||
50 | set(pkg_conf_file "${CMAKE_CURRENT_SOURCE_DIR}/ccd.pc") | |
51 | configure_file("${pkg_conf_file}.in" "${pkg_conf_file}" @ONLY) | |
52 | ||
53 | install(TARGETS ccd ccd_static ARCHIVE DESTINATION lib${LIB_SUFFIX}/ LIBRARY DESTINATION lib${LIB_SUFFIX}/) | |
54 | install(DIRECTORY src/ccd DESTINATION include FILES_MATCHING PATTERN "*.h") | |
55 | install(FILES "${pkg_conf_file}" DESTINATION lib${LIB_SUFFIX}/pkgconfig/ COMPONENT pkgconfig) | |
56 |
0 | libccd is library for a collision detection between two convex shapes. | |
1 | libccd implements variation on Gilbert–Johnson–Keerthi algorithm plus Expand | |
2 | Polytope Algorithm (EPA) and also implements algorithm Minkowski Portal | |
3 | Refinement (MPR, a.k.a. XenoCollide) as described in Game Programming Gems 7. | |
4 | ||
5 | For more info see home of libccd: http://libccd.danfis.cz. | |
6 | ||
7 | ||
8 | Dependencies | |
9 | ------------- | |
10 | This library is currently based only on standard libraries. | |
11 | The only exception are testsuites that are built on top of CU | |
12 | (cu.danfis.cz) library licensed under LGPL, however only testing depends on | |
13 | it and libccd library itself can be distributed without it. | |
14 | ||
15 | ||
16 | License | |
17 | -------- | |
18 | libccd is licensed under OSI-approved 3-clause BSD License, text of license | |
19 | is distributed along with source code in BSD-LICENSE file. | |
20 | Each file should include license notice, the rest should be considered as | |
21 | licensed under 3-clause BSD License. | |
22 | ||
23 | ||
24 | Compile And Install | |
25 | -------------------- | |
26 | Simply type 'make' and 'make install' in src/ directory. | |
27 | ||
28 | Library libccd is by default compiled in double precision of floating point | |
29 | numbers - you can controll this by options USE_SINGLE/USE_DOUBLE, i.e.: | |
30 | $ make USE_SINGLE=yes | |
31 | will compile library in single precision. | |
32 | ||
33 | Installation directory can be changed by options PREFIX, INCLUDEDIR and | |
34 | LIBDIR. | |
35 | ||
36 | For more info type 'make help'. | |
37 | ||
38 | ||
39 | Compile And Install Using Autotools | |
40 | ------------------------------------ | |
41 | libccd also contains support for autotools: | |
42 | 1) Generate configure script etc.: $ ./bootstrap | |
43 | 2) Create new build/ directory: $ mkdir build && cd build | |
44 | 3) Run configure script: $ ../configure | |
45 | 4) Run make and make install: $ make && make install | |
46 | ||
47 | configure script can change the way libccd is compiled and installed, most | |
48 | significant option is --enable-double-precision which enables double | |
49 | precision (single is default in this case). | |
50 | ||
51 | ||
52 | Usage | |
53 | ------ | |
54 | See ccd.h for public API. | |
55 | In your application include <ccd/ccd.h>, setup ccd_t structure and run some | |
56 | of functions (all functions are reentrant). Then link with libccd.a. | |
57 | ||
58 | ||
59 | Directories | |
60 | ------------ | |
61 | src/ | |
62 | - contains source files of libccd. | |
63 | src/testsuites | |
64 | - testsuites - libccd must be compiled before compiling this. | |
65 | src/testsuites/cu | |
66 | - CU unit testing framework | |
67 | src/testsuites/regressions | |
68 | - files ready for regression tests | |
69 | ||
70 | doc/ | |
71 | - some documentation. |
0 | # This file was generated by CMake for @PROJECT_NAME@ | |
1 | prefix=@CMAKE_INSTALL_PREFIX@ | |
2 | exec_prefix=${prefix} | |
3 | libdir=${prefix}/lib | |
4 | includedir=${prefix}/include | |
5 | ||
6 | Name: @PROJECT_NAME@ | |
7 | Description: @PKG_DESC@ | |
8 | Version: @CCD_VERSION@ | |
9 | Requires: @PKG_EXTERNAL_DEPS@ | |
10 | Libs: -L${libdir} -lccd | |
11 | Cflags: -I${includedir} |
0 | # -*- Autoconf -*- | |
1 | # Process this file with autoconf to produce a configure script. | |
2 | ||
3 | #AC_PREREQ([2.65]) | |
4 | AC_INIT([libccd], [1.5], [danfis@danfis.cz]) | |
5 | AC_CONFIG_SRCDIR([src/ccd.c]) | |
6 | AC_CONFIG_HEADERS([src/ccd/config.h]) | |
7 | AM_INIT_AUTOMAKE | |
8 | ||
9 | # Checks for programs. | |
10 | AC_PROG_CXX | |
11 | AC_PROG_CC | |
12 | AC_PROG_INSTALL | |
13 | AC_DISABLE_SHARED | |
14 | LT_INIT | |
15 | ||
16 | # Checks for libraries. | |
17 | AC_CHECK_LIB([m], [main]) | |
18 | # FIXME: Replace `main' with a function in `-lrt': | |
19 | AC_CHECK_LIB([rt], [main]) | |
20 | ||
21 | # Checks for header files. | |
22 | AC_CHECK_HEADERS([float.h stdlib.h string.h unistd.h]) | |
23 | ||
24 | # Checks for typedefs, structures, and compiler characteristics. | |
25 | AC_TYPE_SIZE_T | |
26 | ||
27 | # Checks for library functions. | |
28 | AC_FUNC_FORK | |
29 | AC_FUNC_REALLOC | |
30 | AC_CHECK_FUNCS([clock_gettime]) | |
31 | ||
32 | use_double=no | |
33 | AC_ARG_ENABLE(double-precision, | |
34 | AS_HELP_STRING([--enable-double-precision], | |
35 | [enable double precision computations instead of single precision]), | |
36 | [use_double=yes]) | |
37 | if test $use_double = no | |
38 | then | |
39 | AC_DEFINE([CCD_SINGLE], [], [use single precision]) | |
40 | else | |
41 | AC_DEFINE([CCD_DOUBLE], [], [use double precision]) | |
42 | fi | |
43 | ||
44 | ||
45 | AC_CONFIG_FILES([Makefile | |
46 | src/Makefile | |
47 | src/testsuites/Makefile | |
48 | src/testsuites/cu/Makefile]) | |
49 | AC_OUTPUT |
0 | # Makefile for Sphinx documentation | |
1 | # | |
2 | ||
3 | # You can set these variables from the command line. | |
4 | SPHINXOPTS = | |
5 | SPHINXBUILD = sphinx-build2 | |
6 | PAPER = | |
7 | BUILDDIR = _build | |
8 | ||
9 | # Internal variables. | |
10 | PAPEROPT_a4 = -D latex_paper_size=a4 | |
11 | PAPEROPT_letter = -D latex_paper_size=letter | |
12 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . | |
13 | # the i18n builder cannot share the environment and doctrees with the others | |
14 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . | |
15 | ||
16 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext | |
17 | ||
18 | help: | |
19 | @echo "Please use \`make <target>' where <target> is one of" | |
20 | @echo " html to make standalone HTML files" | |
21 | @echo " dirhtml to make HTML files named index.html in directories" | |
22 | @echo " singlehtml to make a single large HTML file" | |
23 | @echo " pickle to make pickle files" | |
24 | @echo " json to make JSON files" | |
25 | @echo " htmlhelp to make HTML files and a HTML help project" | |
26 | @echo " qthelp to make HTML files and a qthelp project" | |
27 | @echo " devhelp to make HTML files and a Devhelp project" | |
28 | @echo " epub to make an epub" | |
29 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" | |
30 | @echo " latexpdf to make LaTeX files and run them through pdflatex" | |
31 | @echo " text to make text files" | |
32 | @echo " man to make manual pages" | |
33 | @echo " texinfo to make Texinfo files" | |
34 | @echo " info to make Texinfo files and run them through makeinfo" | |
35 | @echo " gettext to make PO message catalogs" | |
36 | @echo " changes to make an overview of all changed/added/deprecated items" | |
37 | @echo " linkcheck to check all external links for integrity" | |
38 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" | |
39 | ||
40 | clean: | |
41 | -rm -rf $(BUILDDIR)/* | |
42 | ||
43 | html: | |
44 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html | |
45 | @echo | |
46 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." | |
47 | ||
48 | dirhtml: | |
49 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml | |
50 | @echo | |
51 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." | |
52 | ||
53 | singlehtml: | |
54 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml | |
55 | @echo | |
56 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." | |
57 | ||
58 | pickle: | |
59 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle | |
60 | @echo | |
61 | @echo "Build finished; now you can process the pickle files." | |
62 | ||
63 | json: | |
64 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json | |
65 | @echo | |
66 | @echo "Build finished; now you can process the JSON files." | |
67 | ||
68 | htmlhelp: | |
69 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp | |
70 | @echo | |
71 | @echo "Build finished; now you can run HTML Help Workshop with the" \ | |
72 | ".hhp project file in $(BUILDDIR)/htmlhelp." | |
73 | ||
74 | qthelp: | |
75 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp | |
76 | @echo | |
77 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ | |
78 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" | |
79 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libccd.qhcp" | |
80 | @echo "To view the help file:" | |
81 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libccd.qhc" | |
82 | ||
83 | devhelp: | |
84 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp | |
85 | @echo | |
86 | @echo "Build finished." | |
87 | @echo "To view the help file:" | |
88 | @echo "# mkdir -p $$HOME/.local/share/devhelp/libccd" | |
89 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libccd" | |
90 | @echo "# devhelp" | |
91 | ||
92 | epub: | |
93 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub | |
94 | @echo | |
95 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." | |
96 | ||
97 | latex: | |
98 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |
99 | @echo | |
100 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." | |
101 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ | |
102 | "(use \`make latexpdf' here to do that automatically)." | |
103 | ||
104 | latexpdf: | |
105 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |
106 | @echo "Running LaTeX files through pdflatex..." | |
107 | $(MAKE) -C $(BUILDDIR)/latex all-pdf | |
108 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." | |
109 | ||
110 | text: | |
111 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text | |
112 | @echo | |
113 | @echo "Build finished. The text files are in $(BUILDDIR)/text." | |
114 | ||
115 | man: | |
116 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man | |
117 | @echo | |
118 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." | |
119 | ||
120 | texinfo: | |
121 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo | |
122 | @echo | |
123 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." | |
124 | @echo "Run \`make' in that directory to run these through makeinfo" \ | |
125 | "(use \`make info' here to do that automatically)." | |
126 | ||
127 | info: | |
128 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo | |
129 | @echo "Running Texinfo files through makeinfo..." | |
130 | make -C $(BUILDDIR)/texinfo info | |
131 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." | |
132 | ||
133 | gettext: | |
134 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale | |
135 | @echo | |
136 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." | |
137 | ||
138 | changes: | |
139 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes | |
140 | @echo | |
141 | @echo "The overview file is in $(BUILDDIR)/changes." | |
142 | ||
143 | linkcheck: | |
144 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck | |
145 | @echo | |
146 | @echo "Link check complete; look for any errors in the above output " \ | |
147 | "or in $(BUILDDIR)/linkcheck/output.txt." | |
148 | ||
149 | doctest: | |
150 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest | |
151 | @echo "Testing of doctests in the sources finished, look at the " \ | |
152 | "results in $(BUILDDIR)/doctest/output.txt." |
0 | Compile And Install | |
1 | ==================== | |
2 | ||
3 | libccd contains several mechanisms how to compile and install it. | |
4 | Using a simple Makefile, using autotools and using CMake. | |
5 | ||
6 | ||
7 | 1. Using Makefile | |
8 | ------------------ | |
9 | Directory ``src/`` contains Makefile that should contain everything needed for compilation and installation: | |
10 | ||
11 | .. code-block:: bash | |
12 | ||
13 | $ cd src/ | |
14 | $ make | |
15 | $ make install | |
16 | ||
17 | Library libccd is by default compiled in double precision of floating point | |
18 | numbers - you can change this by options ``USE_SINGLE``/``USE_DOUBLE``, i.e.: | |
19 | ||
20 | .. code-block:: bash | |
21 | ||
22 | $ make USE_SINGLE=yes | |
23 | ||
24 | will compile library in single precision. | |
25 | Installation directory can be changed by options ``PREFIX``, ``INCLUDEDIR`` | |
26 | and ``LIBDIR``. | |
27 | For more info type '``make help``'. | |
28 | ||
29 | ||
30 | 2. Using Autotools | |
31 | ------------------- | |
32 | libccd also contains support for autotools: | |
33 | Generate configure script etc.: | |
34 | ||
35 | .. code-block:: bash | |
36 | ||
37 | $ ./bootstrap | |
38 | ||
39 | Create new ``build/`` directory: | |
40 | ||
41 | .. code-block:: bash | |
42 | ||
43 | $ mkdir build && cd build | |
44 | ||
45 | Run configure script: | |
46 | ||
47 | .. code-block:: bash | |
48 | ||
49 | $ ../configure | |
50 | ||
51 | Run make and make install: | |
52 | ||
53 | .. code-block:: bash | |
54 | ||
55 | $ make && make install | |
56 | ||
57 | configure script can change the way libccd is compiled and installed, most | |
58 | significant option is ``--enable-double-precision`` which enables double | |
59 | precision (single is default in this case). | |
60 | ||
61 | 3. Using CMake | |
62 | --------------- | |
63 | TODO |
0 | # -*- coding: utf-8 -*- | |
1 | # | |
2 | # libccd documentation build configuration file, created by | |
3 | # sphinx-quickstart2 on Thu May 23 13:49:12 2013. | |
4 | # | |
5 | # This file is execfile()d with the current directory set to its containing dir. | |
6 | # | |
7 | # Note that not all possible configuration values are present in this | |
8 | # autogenerated file. | |
9 | # | |
10 | # All configuration values have a default; values that are commented out | |
11 | # serve to show the default. | |
12 | ||
13 | import sys, os | |
14 | ||
15 | # If extensions (or modules to document with autodoc) are in another directory, | |
16 | # add these directories to sys.path here. If the directory is relative to the | |
17 | # documentation root, use os.path.abspath to make it absolute, like shown here. | |
18 | #sys.path.insert(0, os.path.abspath('.')) | |
19 | ||
20 | # -- General configuration ----------------------------------------------------- | |
21 | ||
22 | # If your documentation needs a minimal Sphinx version, state it here. | |
23 | #needs_sphinx = '1.0' | |
24 | ||
25 | # Add any Sphinx extension module names here, as strings. They can be extensions | |
26 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. | |
27 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.pngmath', 'sphinx.ext.mathjax'] | |
28 | ||
29 | # Add any paths that contain templates here, relative to this directory. | |
30 | templates_path = ['_templates'] | |
31 | ||
32 | # The suffix of source filenames. | |
33 | source_suffix = '.rst' | |
34 | ||
35 | # The encoding of source files. | |
36 | #source_encoding = 'utf-8-sig' | |
37 | ||
38 | # The master toctree document. | |
39 | master_doc = 'index' | |
40 | ||
41 | # General information about the project. | |
42 | project = u'libccd' | |
43 | copyright = u'2013, Daniel Fiser <danfis@danfis.cz>' | |
44 | ||
45 | # The version info for the project you're documenting, acts as replacement for | |
46 | # |version| and |release|, also used in various other places throughout the | |
47 | # built documents. | |
48 | # | |
49 | # The short X.Y version. | |
50 | version = '1.5' | |
51 | # The full version, including alpha/beta/rc tags. | |
52 | release = '1.5' | |
53 | ||
54 | # The language for content autogenerated by Sphinx. Refer to documentation | |
55 | # for a list of supported languages. | |
56 | #language = None | |
57 | ||
58 | # There are two options for replacing |today|: either, you set today to some | |
59 | # non-false value, then it is used: | |
60 | #today = '' | |
61 | # Else, today_fmt is used as the format for a strftime call. | |
62 | #today_fmt = '%B %d, %Y' | |
63 | ||
64 | # List of patterns, relative to source directory, that match files and | |
65 | # directories to ignore when looking for source files. | |
66 | exclude_patterns = ['_build'] | |
67 | ||
68 | # The reST default role (used for this markup: `text`) to use for all documents. | |
69 | #default_role = None | |
70 | ||
71 | # If true, '()' will be appended to :func: etc. cross-reference text. | |
72 | #add_function_parentheses = True | |
73 | ||
74 | # If true, the current module name will be prepended to all description | |
75 | # unit titles (such as .. function::). | |
76 | #add_module_names = True | |
77 | ||
78 | # If true, sectionauthor and moduleauthor directives will be shown in the | |
79 | # output. They are ignored by default. | |
80 | #show_authors = False | |
81 | ||
82 | # The name of the Pygments (syntax highlighting) style to use. | |
83 | pygments_style = 'sphinx' | |
84 | ||
85 | # A list of ignored prefixes for module index sorting. | |
86 | #modindex_common_prefix = [] | |
87 | ||
88 | ||
89 | # -- Options for HTML output --------------------------------------------------- | |
90 | ||
91 | # The theme to use for HTML and HTML Help pages. See the documentation for | |
92 | # a list of builtin themes. | |
93 | html_theme = 'default' | |
94 | ||
95 | # Theme options are theme-specific and customize the look and feel of a theme | |
96 | # further. For a list of options available for each theme, see the | |
97 | # documentation. | |
98 | #html_theme_options = {} | |
99 | ||
100 | # Add any paths that contain custom themes here, relative to this directory. | |
101 | #html_theme_path = [] | |
102 | ||
103 | # The name for this set of Sphinx documents. If None, it defaults to | |
104 | # "<project> v<release> documentation". | |
105 | #html_title = None | |
106 | ||
107 | # A shorter title for the navigation bar. Default is the same as html_title. | |
108 | #html_short_title = None | |
109 | ||
110 | # The name of an image file (relative to this directory) to place at the top | |
111 | # of the sidebar. | |
112 | #html_logo = None | |
113 | ||
114 | # The name of an image file (within the static path) to use as favicon of the | |
115 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 | |
116 | # pixels large. | |
117 | #html_favicon = None | |
118 | ||
119 | # Add any paths that contain custom static files (such as style sheets) here, | |
120 | # relative to this directory. They are copied after the builtin static files, | |
121 | # so a file named "default.css" will overwrite the builtin "default.css". | |
122 | html_static_path = ['_static'] | |
123 | ||
124 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, | |
125 | # using the given strftime format. | |
126 | #html_last_updated_fmt = '%b %d, %Y' | |
127 | ||
128 | # If true, SmartyPants will be used to convert quotes and dashes to | |
129 | # typographically correct entities. | |
130 | #html_use_smartypants = True | |
131 | ||
132 | # Custom sidebar templates, maps document names to template names. | |
133 | #html_sidebars = {} | |
134 | ||
135 | # Additional templates that should be rendered to pages, maps page names to | |
136 | # template names. | |
137 | #html_additional_pages = {} | |
138 | ||
139 | # If false, no module index is generated. | |
140 | #html_domain_indices = True | |
141 | ||
142 | # If false, no index is generated. | |
143 | #html_use_index = True | |
144 | ||
145 | # If true, the index is split into individual pages for each letter. | |
146 | #html_split_index = False | |
147 | ||
148 | # If true, links to the reST sources are added to the pages. | |
149 | #html_show_sourcelink = True | |
150 | ||
151 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. | |
152 | #html_show_sphinx = True | |
153 | ||
154 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. | |
155 | #html_show_copyright = True | |
156 | ||
157 | # If true, an OpenSearch description file will be output, and all pages will | |
158 | # contain a <link> tag referring to it. The value of this option must be the | |
159 | # base URL from which the finished HTML is served. | |
160 | #html_use_opensearch = '' | |
161 | ||
162 | # This is the file name suffix for HTML files (e.g. ".xhtml"). | |
163 | #html_file_suffix = None | |
164 | ||
165 | # Output file base name for HTML help builder. | |
166 | htmlhelp_basename = 'libccddoc' | |
167 | ||
168 | ||
169 | # -- Options for LaTeX output -------------------------------------------------- | |
170 | ||
171 | latex_elements = { | |
172 | # The paper size ('letterpaper' or 'a4paper'). | |
173 | #'papersize': 'letterpaper', | |
174 | ||
175 | # The font size ('10pt', '11pt' or '12pt'). | |
176 | #'pointsize': '10pt', | |
177 | ||
178 | # Additional stuff for the LaTeX preamble. | |
179 | #'preamble': '', | |
180 | } | |
181 | ||
182 | # Grouping the document tree into LaTeX files. List of tuples | |
183 | # (source start file, target name, title, author, documentclass [howto/manual]). | |
184 | latex_documents = [ | |
185 | ('index', 'libccd.tex', u'libccd Documentation', | |
186 | u'Daniel Fiser', 'manual'), | |
187 | ] | |
188 | ||
189 | # The name of an image file (relative to this directory) to place at the top of | |
190 | # the title page. | |
191 | #latex_logo = None | |
192 | ||
193 | # For "manual" documents, if this is true, then toplevel headings are parts, | |
194 | # not chapters. | |
195 | #latex_use_parts = False | |
196 | ||
197 | # If true, show page references after internal links. | |
198 | #latex_show_pagerefs = False | |
199 | ||
200 | # If true, show URL addresses after external links. | |
201 | #latex_show_urls = False | |
202 | ||
203 | # Documents to append as an appendix to all manuals. | |
204 | #latex_appendices = [] | |
205 | ||
206 | # If false, no module index is generated. | |
207 | #latex_domain_indices = True | |
208 | ||
209 | ||
210 | # -- Options for manual page output -------------------------------------------- | |
211 | ||
212 | # One entry per manual page. List of tuples | |
213 | # (source start file, name, description, authors, manual section). | |
214 | man_pages = [ | |
215 | ('index', 'libccd', u'libccd Documentation', | |
216 | [u'Daniel Fiser'], 1) | |
217 | ] | |
218 | ||
219 | # If true, show URL addresses after external links. | |
220 | #man_show_urls = False | |
221 | ||
222 | ||
223 | # -- Options for Texinfo output ------------------------------------------------ | |
224 | ||
225 | # Grouping the document tree into Texinfo files. List of tuples | |
226 | # (source start file, target name, title, author, | |
227 | # dir menu entry, description, category) | |
228 | texinfo_documents = [ | |
229 | ('index', 'libccd', u'libccd Documentation', | |
230 | u'Daniel Fiser', 'libccd', 'One line description of project.', | |
231 | 'Miscellaneous'), | |
232 | ] | |
233 | ||
234 | # Documents to append as an appendix to all manuals. | |
235 | #texinfo_appendices = [] | |
236 | ||
237 | # If false, no module index is generated. | |
238 | #texinfo_domain_indices = True | |
239 | ||
240 | # How to display URL addresses: 'footnote', 'no', or 'inline'. | |
241 | #texinfo_show_urls = 'footnote' |
0 | Example of Usage | |
1 | ================= | |
2 | ||
3 | 1. GJK - Intersection Test | |
4 | --------------------------- | |
5 | This section describes how to use **libccd** for testing if two convex objects intersects (i.e., 'yes/no' test) using Gilbert-Johnson-Keerthi (GJK) algorithm. | |
6 | ||
7 | Procedure is very simple (and similar to the usage of the rest of the | |
8 | library): | |
9 | ||
10 | #. Include ``<ccd/ccd.h>`` file. | |
11 | #. Implement support function for specific shapes. Support function is | |
12 | function that returns furthest point from object (shape) in specified | |
13 | direction. | |
14 | #. Set up ``ccd_t`` structure. | |
15 | #. Run ``ccdGJKIntersect()`` function on desired objects. | |
16 | ||
17 | ||
18 | Here is a skeleton of simple program: | |
19 | ||
20 | .. code-block:: c | |
21 | ||
22 | #include <ccd/ccd.h> | |
23 | #include <ccd/quat.h> // for work with quaternions | |
24 | ||
25 | /** Support function for box */ | |
26 | void support(const void *obj, const ccd_vec3_t *dir, | |
27 | ccd_vec3_t *vec) | |
28 | { | |
29 | // assume that obj_t is user-defined structure that holds info about | |
30 | // object (in this case box: x, y, z, pos, quat - dimensions of box, | |
31 | // position and rotation) | |
32 | obj_t *obj = (obj_t *)_obj; | |
33 | ccd_vec3_t dir; | |
34 | ccd_quat_t qinv; | |
35 | ||
36 | // apply rotation on direction vector | |
37 | ccdVec3Copy(&dir, _dir); | |
38 | ccdQuatInvert2(&qinv, &obj->quat); | |
39 | ccdQuatRotVec(&dir, &qinv); | |
40 | ||
41 | // compute support point in specified direction | |
42 | ccdVec3Set(v, ccdSign(ccdVec3X(&dir)) * box->x * CCD_REAL(0.5), | |
43 | ccdSign(ccdVec3Y(&dir)) * box->y * CCD_REAL(0.5), | |
44 | ccdSign(ccdVec3Z(&dir)) * box->z * CCD_REAL(0.5)); | |
45 | ||
46 | // transform support point according to position and rotation of object | |
47 | ccdQuatRotVec(v, &obj->quat); | |
48 | ccdVec3Add(v, &obj->pos); | |
49 | } | |
50 | ||
51 | ||
52 | int main(int argc, char *argv[]) | |
53 | { | |
54 | ... | |
55 | ||
56 | ccd_t ccd; | |
57 | CCD_INIT(&ccd); // initialize ccd_t struct | |
58 | ||
59 | // set up ccd_t struct | |
60 | ccd.support1 = support; // support function for first object | |
61 | ccd.support2 = support; // support function for second object | |
62 | ccd.max_iterations = 100; // maximal number of iterations | |
63 | ||
64 | int intersect = ccdGJKIntersect(obj1, obj2, &ccd); | |
65 | // now intersect holds true if obj1 and obj2 intersect, false otherwise | |
66 | } | |
67 | ||
68 | ||
69 | ||
70 | ||
71 | 2. GJK + EPA - Penetration Of Two Objects | |
72 | ------------------------------------------ | |
73 | ||
74 | If you want to obtain also penetration info about two intersection objects | |
75 | ``ccdGJKPenetration()`` function can be used. | |
76 | ||
77 | Procedure is almost the same as for the previous case: | |
78 | ||
79 | .. code-block:: c | |
80 | ||
81 | #include <ccd/ccd.h> | |
82 | #include <ccd/quat.h> // for work with quaternions | |
83 | ||
84 | /** Support function is same as in previous case */ | |
85 | ||
86 | int main(int argc, char *argv[]) | |
87 | { | |
88 | ... | |
89 | ccd_t ccd; | |
90 | CCD_INIT(&ccd); // initialize ccd_t struct | |
91 | ||
92 | // set up ccd_t struct | |
93 | ccd.support1 = support; // support function for first object | |
94 | ccd.support2 = support; // support function for second object | |
95 | ccd.max_iterations = 100; // maximal number of iterations | |
96 | ccd.epa_tolerance = 0.0001; // maximal tolerance fro EPA part | |
97 | ||
98 | ccd_real_t depth; | |
99 | ccd_vec3_t dir, pos; | |
100 | int intersect = ccdGJKPenetration(obj1, obj2, &ccd, &depth, &dir, &pos); | |
101 | // now intersect holds true if obj1 and obj2 intersect, false otherwise | |
102 | // in depth, dir and pos is stored penetration depth, direction of | |
103 | // separation vector and position in global coordinate system | |
104 | } | |
105 | ||
106 | ||
107 | 3. MPR - Intersection Test | |
108 | --------------------------- | |
109 | ||
110 | **libccd** also provides *MPR* - Minkowski Portal Refinement algorithm that | |
111 | can be used for testing if two objects intersects. | |
112 | ||
113 | Procedure is similar to the one used for GJK algorithm. Support function is | |
114 | the same but also function that returns a center (or any point near center) | |
115 | of a given object must be implemented: | |
116 | ||
117 | .. code-block:: c | |
118 | ||
119 | #include <ccd/ccd.h> | |
120 | #include <ccd/quat.h> // for work with quaternions | |
121 | ||
122 | /** Support function is same as in previous case */ | |
123 | ||
124 | /** Center function - returns center of object */ | |
125 | void center(const void *_obj, ccd_vec3_t *center) | |
126 | { | |
127 | obj_t *obj = (obj_t *)_obj; | |
128 | ccdVec3Copy(center, &obj->pos); | |
129 | } | |
130 | ||
131 | int main(int argc, char *argv[]) | |
132 | { | |
133 | ... | |
134 | ccd_t ccd; | |
135 | CCD_INIT(&ccd); // initialize ccd_t struct | |
136 | ||
137 | // set up ccd_t struct | |
138 | ccd.support1 = support; // support function for first object | |
139 | ccd.support2 = support; // support function for second object | |
140 | ccd.center1 = center; // center function for first object | |
141 | ccd.center2 = center; // center function for second object | |
142 | ccd.mpr_tolerance = 0.0001; // maximal tolerance | |
143 | ||
144 | int intersect = ccdMPRIntersect(obj1, obj2, &ccd); | |
145 | // now intersect holds true if obj1 and obj2 intersect, false otherwise | |
146 | } | |
147 | ||
148 | ||
149 | 4. MPR - Penetration Of Two Objects | |
150 | ------------------------------------ | |
151 | ||
152 | Using MPR algorithm for obtaining penetration info about two intersection | |
153 | objects is equally easy as in the previous case instead but | |
154 | ``ccdMPRPenetration()`` function is used: | |
155 | ||
156 | .. code-block:: c | |
157 | ||
158 | #include <ccd/ccd.h> | |
159 | #include <ccd/quat.h> // for work with quaternions | |
160 | ||
161 | /** Support function is same as in previous case */ | |
162 | /** Center function is same as in prevous case */ | |
163 | ||
164 | int main(int argc, char *argv[]) | |
165 | { | |
166 | ... | |
167 | ccd_t ccd; | |
168 | CCD_INIT(&ccd); // initialize ccd_t struct | |
169 | ||
170 | // set up ccd_t struct | |
171 | ccd.support1 = support; // support function for first object | |
172 | ccd.support2 = support; // support function for second object | |
173 | ccd.center1 = center; // center function for first object | |
174 | ccd.center2 = center; // center function for second object | |
175 | ccd.mpr_tolerance = 0.0001; // maximal tolerance | |
176 | ||
177 | ccd_real_t depth; | |
178 | ccd_vec3_t dir, pos; | |
179 | int intersect = ccdMPRPenetration(obj1, obj2, &ccd, &depth, &dir, &pos); | |
180 | // now intersect holds true if obj1 and obj2 intersect, false otherwise | |
181 | // in depth, dir and pos is stored penetration depth, direction of | |
182 | // separation vector and position in global coordinate system | |
183 | } | |
184 |
0 | .. libccd documentation master file, created by | |
1 | sphinx-quickstart2 on Thu May 23 13:49:12 2013. | |
2 | ||
3 | libccd's documentation | |
4 | ======================= | |
5 | ||
6 | See homepage: http://libccd.danfis.cz | |
7 | ||
8 | Contents: | |
9 | ||
10 | .. toctree:: | |
11 | :maxdepth: 2 | |
12 | ||
13 | compile-and-install.rst | |
14 | examples.rst | |
15 | reference.rst | |
16 | ||
17 | ||
18 | .. Indices and tables | |
19 | .. ================== | |
20 | ||
21 | .. * :ref:`genindex` | |
22 | .. * :ref:`modindex` | |
23 | .. * :ref:`search` | |
24 |
Binary diff not shown
0 | #!/bin/bash | |
1 | ||
2 | # Creates .tar.gz package of specified version. | |
3 | # Takes one argument - identification of commit | |
4 | ||
5 | NAME=libccd | |
6 | COMMIT="" | |
7 | CMD="git archive" | |
8 | ||
9 | # read arguments | |
10 | COMMIT="$1" | |
11 | ||
12 | if [ "$COMMIT" = "" ]; then | |
13 | echo "Usage: $0 commit [--notest] [--nodoc]" | |
14 | echo "Error: you must specify commit which should be packed" | |
15 | exit -1; | |
16 | fi; | |
17 | ||
18 | ||
19 | PREFIX=${NAME}-$COMMIT/ | |
20 | FN=${NAME}-$COMMIT.tar.gz | |
21 | ||
22 | if echo "$COMMIT" | grep '^v[0-9]\.[0-9]\+' >/dev/null 2>&1; then | |
23 | tmp=$(echo "$COMMIT" | sed 's/^v//') | |
24 | PREFIX=${NAME}-$tmp/ | |
25 | FN=${NAME}-$tmp.tar.gz | |
26 | fi | |
27 | ||
28 | $CMD --prefix="$PREFIX" --format=tar $COMMIT | gzip >"$FN" | |
29 | echo "Package: $FN" | |
30 |
0 | ### | |
1 | # libccd | |
2 | # --------------------------------- | |
3 | # Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | # | |
5 | # | |
6 | # This file is part of libccd. | |
7 | # | |
8 | # Distributed under the OSI-approved BSD License (the "License"); | |
9 | # see accompanying file BDS-LICENSE for details or see | |
10 | # <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | # | |
12 | # This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | # See the License for more information. | |
15 | ## | |
16 | ||
17 | -include Makefile.include | |
18 | ||
19 | CFLAGS += -I. | |
20 | ||
21 | TARGETS = libccd.a | |
22 | OBJS = ccd.o mpr.o support.o vec3.o polytope.o | |
23 | ||
24 | all: $(TARGETS) | |
25 | ||
26 | libccd.a: $(OBJS) | |
27 | ar cr $@ $(OBJS) | |
28 | ranlib $@ | |
29 | ||
30 | ccd/config.h: ccd/config.h.m4 | |
31 | $(M4) $(CONFIG_FLAGS) $< >$@ | |
32 | ||
33 | %.o: %.c %.h ccd/config.h | |
34 | $(CC) $(CFLAGS) $(DEFS) -c -o $@ $< | |
35 | %.o: %.c ccd/config.h | |
36 | $(CC) $(CFLAGS) $(DEFS) -c -o $@ $< | |
37 | %.h: ccd/config.h | |
38 | %.c: ccd/config.h | |
39 | ||
40 | install: | |
41 | mkdir -p $(PREFIX)/$(INCLUDEDIR)/ccd | |
42 | mkdir -p $(PREFIX)/$(LIBDIR) | |
43 | cp ccd/*.h $(PREFIX)/$(INCLUDEDIR)/ccd/ | |
44 | cp libccd.a $(PREFIX)/$(LIBDIR) | |
45 | ||
46 | clean: | |
47 | rm -f $(OBJS) | |
48 | rm -f $(TARGETS) | |
49 | rm -f ccd/config.h | |
50 | if [ -d testsuites ]; then $(MAKE) -C testsuites clean; fi; | |
51 | ||
52 | check: | |
53 | $(MAKE) -C testsuites check | |
54 | check-valgrind: | |
55 | $(MAKE) -C testsuites check-valgrind | |
56 | ||
57 | help: | |
58 | @echo "Targets:" | |
59 | @echo " all - Build library" | |
60 | @echo " install - Install library into system" | |
61 | @echo "" | |
62 | @echo "Options:" | |
63 | @echo " CC - Path to C compiler" | |
64 | @echo " M4 - Path to m4 macro processor" | |
65 | @echo "" | |
66 | @echo " DEBUG 'yes'/'no' - Turn on/off debugging (default: 'no')" | |
67 | @echo " PROFIL 'yes'/'no' - Compiles profiling info (default: 'no')" | |
68 | @echo " NOWALL 'yes'/'no' - Turns off -Wall gcc option (default: 'no')" | |
69 | @echo " NOPEDANTIC 'yes'/'no' - Turns off -pedantic gcc option (default: 'no')" | |
70 | @echo "" | |
71 | @echo " USE_SINGLE 'yes' - Use single precision (default: 'no')" | |
72 | @echo " USE_DOUBLE 'yes' - Use double precision (default: 'yes')" | |
73 | @echo "" | |
74 | @echo " PREFIX - Prefix where library will be installed (default: /usr/local)" | |
75 | @echo " INCLUDEDIR - Directory where header files will be installed (PREFIX/INCLUDEDIR) (default: include)" | |
76 | @echo " LIBDIR - Directory where library will be installed (PREFIX/LIBDIR) (default: lib)" | |
77 | @echo "" | |
78 | ||
79 | .PHONY: all clean check check-valgrind help |
0 | SUBDIRS = . testsuites | |
1 | ||
2 | lib_LTLIBRARIES = libccd.la | |
3 | ||
4 | libccd_la_SOURCES = ccd/alloc.h \ | |
5 | ccd/compiler.h \ | |
6 | ccd/dbg.h \ | |
7 | ccd.c ccd/ccd.h \ | |
8 | ccd/list.h \ | |
9 | polytope.c ccd/polytope.h \ | |
10 | ccd/quat.h \ | |
11 | ccd/simplex.h \ | |
12 | support.c ccd/support.h \ | |
13 | vec3.c ccd/vec3.h \ | |
14 | mpr.c | |
15 |
0 | ### | |
1 | # libccd | |
2 | # --------------------------------- | |
3 | # Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | # | |
5 | # | |
6 | # This file is part of libccd. | |
7 | # | |
8 | # Distributed under the OSI-approved BSD License (the "License"); | |
9 | # see accompanying file BDS-LICENSE for details or see | |
10 | # <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | # | |
12 | # This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | # See the License for more information. | |
15 | ## | |
16 | ||
17 | CC ?= gcc | |
18 | M4 ?= m4 | |
19 | PYTHON ?= python | |
20 | ||
21 | SYSTEM = $(shell uname) | |
22 | ||
23 | SYSTEM_CXXFLAGS = | |
24 | SYSTEM_LDFLAGS = | |
25 | ||
26 | ifeq '$(SYSTEM)' 'FreeBSD' | |
27 | SYSTEM_CXXFLAGS = -Wno-long-long | |
28 | else | |
29 | endif | |
30 | ||
31 | NOWALL ?= no | |
32 | NOPEDANTIC ?= no | |
33 | DEBUG ?= no | |
34 | PROFIL ?= no | |
35 | ||
36 | ifeq '$(PROFIL)' 'yes' | |
37 | DEBUG = yes | |
38 | endif | |
39 | ||
40 | ifeq '$(DEBUG)' 'yes' | |
41 | CFLAGS = -g | |
42 | endif | |
43 | ifeq '$(PROFIL)' 'yes' | |
44 | CFLAGS += -pg | |
45 | endif | |
46 | ||
47 | ifneq '$(NOWALL)' 'yes' | |
48 | CFLAGS += -Wall | |
49 | endif | |
50 | ifneq '$(NOPEDANTIC)' 'yes' | |
51 | CFLAGS += -pedantic | |
52 | endif | |
53 | ||
54 | CONFIG_FLAGS = | |
55 | USE_DOUBLE ?= yes | |
56 | USE_SINGLE ?= no | |
57 | ||
58 | ifeq '$(USE_SINGLE)' 'yes' | |
59 | CONFIG_FLAGS += -DUSE_SINGLE | |
60 | USE_DOUBLE = no | |
61 | endif | |
62 | ifeq '$(USE_DOUBLE)' 'yes' | |
63 | CONFIG_FLAGS += -DUSE_DOUBLE | |
64 | endif | |
65 | ||
66 | CFLAGS += --std=gnu99 | |
67 | LDFLAGS += $(SYSTEM_LDFLAGS) | |
68 | ||
69 | CHECKTARGETS = | |
70 | check-dep: $(CHECKTARGETS) | |
71 | ||
72 | PREFIX ?= /usr/local | |
73 | INCLUDEDIR ?= include | |
74 | LIBDIR ?= lib | |
75 | ||
76 | showvars: | |
77 | @echo "SYSTEM = "$(SYSTEM) | |
78 | @echo "" | |
79 | @echo "CC = $(CC)" | |
80 | @echo "M4 = $(M4)" | |
81 | @echo "" | |
82 | @echo "DEBUG = $(DEBUG)" | |
83 | @echo "PROFIL = $(PROFIL)" | |
84 | @echo "NOWALL = $(NOWALL)" | |
85 | @echo "NOPEDANTIC = $(NOPEDANTIC)" | |
86 | @echo "USE_SINGLE = $(USE_SINGLE)" | |
87 | @echo "USE_DOUBLE = $(USE_DOUBLE)" | |
88 | @echo "" | |
89 | @echo "CFLAGS = $(CFLAGS)" | |
90 | @echo "LDFLAGS = $(LDFLAGS)" | |
91 | @echo "CONFIG_FLAGS = $(CONFIG_FLAGS)" | |
92 | @echo "" | |
93 | @echo "PREFIX = $(PREFIX)" | |
94 | @echo "INCLUDEDIR = $(INCLUDEDIR)" | |
95 | @echo "LIBDIR = $(LIBDIR)" | |
96 | @echo "" | |
97 | ||
98 | .DEFAULT_GOAL := all | |
99 | .PHONY: showvars |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_ALLOC_H__ | |
18 | #define __CCD_ALLOC_H__ | |
19 | ||
20 | #include <stdlib.h> | |
21 | ||
22 | #ifdef __cplusplus | |
23 | extern "C" { | |
24 | #endif /* __cplusplus */ | |
25 | ||
26 | /** | |
27 | * Functions and macros required for memory allocation. | |
28 | */ | |
29 | ||
30 | /* Memory allocation: */ | |
31 | #define __CCD_ALLOC_MEMORY(type, ptr_old, size) \ | |
32 | (type *)realloc((void *)ptr_old, (size)) | |
33 | ||
34 | /** Allocate memory for one element of type. */ | |
35 | #define CCD_ALLOC(type) \ | |
36 | __CCD_ALLOC_MEMORY(type, NULL, sizeof(type)) | |
37 | ||
38 | /** Allocate memory for array of elements of type type. */ | |
39 | #define CCD_ALLOC_ARR(type, num_elements) \ | |
40 | __CCD_ALLOC_MEMORY(type, NULL, sizeof(type) * (num_elements)) | |
41 | ||
42 | #define CCD_REALLOC_ARR(ptr, type, num_elements) \ | |
43 | __CCD_ALLOC_MEMORY(type, ptr, sizeof(type) * (num_elements)) | |
44 | ||
45 | #ifdef __cplusplus | |
46 | } /* extern "C" */ | |
47 | #endif /* __cplusplus */ | |
48 | ||
49 | #endif /* __CCD_ALLOC_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010,2011 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_H__ | |
18 | #define __CCD_H__ | |
19 | ||
20 | #include <ccd/vec3.h> | |
21 | ||
22 | #ifdef __cplusplus | |
23 | extern "C" { | |
24 | #endif /* __cplusplus */ | |
25 | ||
26 | /** | |
27 | * Type of *support* function that takes pointer to 3D object and direction | |
28 | * and returns (via vec argument) furthest point from object in specified | |
29 | * direction. | |
30 | */ | |
31 | typedef void (*ccd_support_fn)(const void *obj, const ccd_vec3_t *dir, | |
32 | ccd_vec3_t *vec); | |
33 | ||
34 | /** | |
35 | * Returns (via dir argument) first direction vector that will be used in | |
36 | * initialization of algorithm. | |
37 | */ | |
38 | typedef void (*ccd_first_dir_fn)(const void *obj1, const void *obj2, | |
39 | ccd_vec3_t *dir); | |
40 | ||
41 | ||
42 | /** | |
43 | * Returns (via center argument) geometric center (some point near center) | |
44 | * of given object. | |
45 | */ | |
46 | typedef void (*ccd_center_fn)(const void *obj1, ccd_vec3_t *center); | |
47 | ||
48 | /** | |
49 | * Main structure of CCD algorithm. | |
50 | */ | |
51 | struct _ccd_t { | |
52 | ccd_first_dir_fn first_dir; //!< Returns initial direction where first | |
53 | //!< support point will be searched | |
54 | ccd_support_fn support1; //!< Function that returns support point of | |
55 | //!< first object | |
56 | ccd_support_fn support2; //!< Function that returns support point of | |
57 | //!< second object | |
58 | ||
59 | ccd_center_fn center1; //!< Function that returns geometric center of | |
60 | //!< first object | |
61 | ccd_center_fn center2; //!< Function that returns geometric center of | |
62 | //!< second object | |
63 | ||
64 | unsigned long max_iterations; //!< Maximal number of iterations | |
65 | ccd_real_t epa_tolerance; | |
66 | ccd_real_t mpr_tolerance; //!< Boundary tolerance for MPR algorithm | |
67 | ccd_real_t dist_tolerance; | |
68 | }; | |
69 | typedef struct _ccd_t ccd_t; | |
70 | ||
71 | /** | |
72 | * Default first direction. | |
73 | */ | |
74 | void ccdFirstDirDefault(const void *o1, const void *o2, ccd_vec3_t *dir); | |
75 | ||
76 | #define CCD_INIT(ccd) \ | |
77 | do { \ | |
78 | (ccd)->first_dir = ccdFirstDirDefault; \ | |
79 | (ccd)->support1 = NULL; \ | |
80 | (ccd)->support2 = NULL; \ | |
81 | (ccd)->center1 = NULL; \ | |
82 | (ccd)->center2 = NULL; \ | |
83 | \ | |
84 | (ccd)->max_iterations = (unsigned long)-1; \ | |
85 | (ccd)->epa_tolerance = CCD_REAL(0.0001); \ | |
86 | (ccd)->mpr_tolerance = CCD_REAL(0.0001); \ | |
87 | (ccd)->dist_tolerance = CCD_REAL(1E-6); \ | |
88 | } while(0) | |
89 | ||
90 | ||
91 | /** | |
92 | * Returns true if two given objects interest. | |
93 | */ | |
94 | int ccdGJKIntersect(const void *obj1, const void *obj2, const ccd_t *ccd); | |
95 | ||
96 | /** | |
97 | * This function computes separation vector of two objects. Separation | |
98 | * vector is minimal translation of obj2 to get obj1 and obj2 speparated | |
99 | * (without intersection). | |
100 | * Returns 0 if obj1 and obj2 intersect and sep is filled with translation | |
101 | * vector. If obj1 and obj2 don't intersect -1 is returned. | |
102 | * If memory allocation fails -2 is returned. | |
103 | */ | |
104 | int ccdGJKSeparate(const void *obj1, const void *obj2, const ccd_t *ccd, | |
105 | ccd_vec3_t *sep); | |
106 | ||
107 | /** | |
108 | * Computes penetration of obj2 into obj1. | |
109 | * Depth of penetration, direction and position is returned. It means that | |
110 | * if obj2 is translated by distance depth in direction dir objects will | |
111 | * have touching contact, pos should be position in global coordinates | |
112 | * where force should take a place. | |
113 | * | |
114 | * CCD+EPA algorithm is used. | |
115 | * | |
116 | * Returns 0 if obj1 and obj2 intersect and depth, dir and pos are filled | |
117 | * if given non-NULL pointers. | |
118 | * If obj1 and obj2 don't intersect -1 is returned. | |
119 | * If memory allocation fails -2 is returned. | |
120 | */ | |
121 | int ccdGJKPenetration(const void *obj1, const void *obj2, const ccd_t *ccd, | |
122 | ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); | |
123 | ||
124 | /** | |
125 | * Returns true if two given objects intersect - MPR algorithm is used. | |
126 | */ | |
127 | int ccdMPRIntersect(const void *obj1, const void *obj2, const ccd_t *ccd); | |
128 | ||
129 | /** | |
130 | * Computes penetration of obj2 into obj1. | |
131 | * Depth of penetration, direction and position is returned, i.e. if obj2 | |
132 | * is translated by computed depth in resulting direction obj1 and obj2 | |
133 | * would have touching contact. Position is point in global coordinates | |
134 | * where force should be take a place. | |
135 | * | |
136 | * Minkowski Portal Refinement algorithm is used (MPR, a.k.a. XenoCollide, | |
137 | * see Game Programming Gem 7). | |
138 | * | |
139 | * Returns 0 if obj1 and obj2 intersect, otherwise -1 is returned. | |
140 | */ | |
141 | int ccdMPRPenetration(const void *obj1, const void *obj2, const ccd_t *ccd, | |
142 | ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); | |
143 | ||
144 | #ifdef __cplusplus | |
145 | } /* extern "C" */ | |
146 | #endif /* __cplusplus */ | |
147 | ||
148 | #endif /* __CCD_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_COMPILER_H__ | |
18 | #define __CCD_COMPILER_H__ | |
19 | ||
20 | #include <stddef.h> | |
21 | ||
22 | #define ccd_offsetof(TYPE, MEMBER) offsetof(TYPE, MEMBER) | |
23 | ||
24 | #define ccd_container_of(ptr, type, member) \ | |
25 | (type *)( (char *)ptr - ccd_offsetof(type, member)) | |
26 | ||
27 | ||
28 | /** | |
29 | * Marks inline function. | |
30 | */ | |
31 | #ifdef __GNUC__ | |
32 | # define _ccd_inline static inline __attribute__((always_inline)) | |
33 | #else /* __GNUC__ */ | |
34 | # define _ccd_inline static __inline | |
35 | #endif /* __GNUC__ */ | |
36 | ||
37 | ||
38 | /** | |
39 | * __prefetch(x) - prefetches the cacheline at "x" for read | |
40 | * __prefetchw(x) - prefetches the cacheline at "x" for write | |
41 | */ | |
42 | #ifdef __GNUC__ | |
43 | # define _ccd_prefetch(x) __builtin_prefetch(x) | |
44 | # define _ccd_prefetchw(x) __builtin_prefetch(x,1) | |
45 | #else /* __GNUC__ */ | |
46 | # define _ccd_prefetch(x) ((void)0) | |
47 | # define _ccd_prefetchw(x) ((void)0) | |
48 | #endif /* __GNUC__ */ | |
49 | ||
50 | ||
51 | #ifdef __ICC | |
52 | // disable unused parameter warning | |
53 | # pragma warning(disable:869) | |
54 | // disable annoying "operands are evaluated in unspecified order" warning | |
55 | # pragma warning(disable:981) | |
56 | #endif /* __ICC */ | |
57 | ||
58 | #endif /* __CCD_COMPILER_H__ */ | |
59 |
0 | #ifndef __CCD_CONFIG_H__ | |
1 | #define __CCD_CONFIG_H__ | |
2 | ||
3 | #cmakedefine CCD_SINGLE | |
4 | #cmakedefine CCD_DOUBLE | |
5 | ||
6 | #endif /* __CCD_CONFIG_H__ */ |
0 | #ifndef __CCD_CONFIG_H__ | |
1 | #define __CCD_CONFIG_H__ | |
2 | ||
3 | ifdef(`USE_SINGLE', `#define CCD_SINGLE') | |
4 | ifdef(`USE_DOUBLE', `#define CCD_DOUBLE') | |
5 | ||
6 | #endif /* __CCD_CONFIG_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_DBG_H__ | |
18 | #define __CCD_DBG_H__ | |
19 | ||
20 | /** | |
21 | * Some macros which can be used for printing debug info to stderr if macro | |
22 | * NDEBUG not defined. | |
23 | * | |
24 | * DBG_PROLOGUE can be specified as string and this string will be | |
25 | * prepended to output text | |
26 | */ | |
27 | #ifndef NDEBUG | |
28 | ||
29 | #include <stdio.h> | |
30 | ||
31 | #ifndef DBG_PROLOGUE | |
32 | # define DBG_PROLOGUE | |
33 | #endif | |
34 | ||
35 | # define DBG(format, ...) do { \ | |
36 | fprintf(stderr, DBG_PROLOGUE "%s :: " format "\n", __func__, ## __VA_ARGS__); \ | |
37 | fflush(stderr); \ | |
38 | } while (0) | |
39 | ||
40 | # define DBG2(str) do { \ | |
41 | fprintf(stderr, DBG_PROLOGUE "%s :: " str "\n", __func__); \ | |
42 | fflush(stderr); \ | |
43 | } while (0) | |
44 | ||
45 | # define DBG_VEC3(vec, prefix) do {\ | |
46 | fprintf(stderr, DBG_PROLOGUE "%s :: %s[%lf %lf %lf]\n", \ | |
47 | __func__, prefix, ccdVec3X(vec), ccdVec3Y(vec), ccdVec3Z(vec)); \ | |
48 | fflush(stderr); \ | |
49 | } while (0) | |
50 | /* | |
51 | # define DBG_VEC3(vec, prefix) do {\ | |
52 | fprintf(stderr, DBG_PROLOGUE "%s :: %s[%.20lf %.20lf %.20lf]\n", \ | |
53 | __func__, prefix, ccdVec3X(vec), ccdVec3Y(vec), ccdVec3Z(vec)); \ | |
54 | fflush(stderr); \ | |
55 | } while (0) | |
56 | */ | |
57 | ||
58 | #else | |
59 | # define DBG(format, ...) | |
60 | # define DBG2(str) | |
61 | # define DBG_VEC3(v, prefix) | |
62 | #endif | |
63 | ||
64 | #endif /* __CCD_DBG_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_LIST_H__ | |
18 | #define __CCD_LIST_H__ | |
19 | ||
20 | #include <string.h> | |
21 | #include <ccd/compiler.h> | |
22 | ||
23 | #ifdef __cplusplus | |
24 | extern "C" { | |
25 | #endif /* __cplusplus */ | |
26 | ||
27 | struct _ccd_list_t { | |
28 | struct _ccd_list_t *next, *prev; | |
29 | }; | |
30 | typedef struct _ccd_list_t ccd_list_t; | |
31 | ||
32 | ||
33 | ||
34 | /** | |
35 | * Get the struct for this entry. | |
36 | * @ptr: the &ccd_list_t pointer. | |
37 | * @type: the type of the struct this is embedded in. | |
38 | * @member: the name of the list_struct within the struct. | |
39 | */ | |
40 | #define ccdListEntry(ptr, type, member) \ | |
41 | ccd_container_of(ptr, type, member) | |
42 | ||
43 | /** | |
44 | * Iterates over list. | |
45 | */ | |
46 | #define ccdListForEach(list, item) \ | |
47 | for (item = (list)->next; \ | |
48 | _ccd_prefetch((item)->next), item != (list); \ | |
49 | item = (item)->next) | |
50 | ||
51 | /** | |
52 | * Iterates over list safe against remove of list entry | |
53 | */ | |
54 | #define ccdListForEachSafe(list, item, tmp) \ | |
55 | for (item = (list)->next, tmp = (item)->next; \ | |
56 | item != (list); \ | |
57 | item = tmp, tmp = (item)->next) | |
58 | ||
59 | /** | |
60 | * Iterates over list of given type. | |
61 | * @pos: the type * to use as a loop cursor. | |
62 | * @head: the head for your list. | |
63 | * @member: the name of the list_struct within the struct. | |
64 | */ | |
65 | #define ccdListForEachEntry(head, pos, postype, member) \ | |
66 | for (pos = ccdListEntry((head)->next, postype, member); \ | |
67 | _ccd_prefetch(pos->member.next), &pos->member != (head); \ | |
68 | pos = ccdListEntry(pos->member.next, postype, member)) | |
69 | ||
70 | /** | |
71 | * Iterates over list of given type safe against removal of list entry | |
72 | * @pos: the type * to use as a loop cursor. | |
73 | * @n: another type * to use as temporary storage | |
74 | * @head: the head for your list. | |
75 | * @member: the name of the list_struct within the struct. | |
76 | */ | |
77 | #define ccdListForEachEntrySafe(head, pos, postype, n, ntype, member) \ | |
78 | for (pos = ccdListEntry((head)->next, postype, member), \ | |
79 | n = ccdListEntry(pos->member.next, postype, member); \ | |
80 | &pos->member != (head); \ | |
81 | pos = n, n = ccdListEntry(n->member.next, ntype, member)) | |
82 | ||
83 | ||
84 | /** | |
85 | * Initialize list. | |
86 | */ | |
87 | _ccd_inline void ccdListInit(ccd_list_t *l); | |
88 | ||
89 | _ccd_inline ccd_list_t *ccdListNext(ccd_list_t *l); | |
90 | _ccd_inline ccd_list_t *ccdListPrev(ccd_list_t *l); | |
91 | ||
92 | /** | |
93 | * Returns true if list is empty. | |
94 | */ | |
95 | _ccd_inline int ccdListEmpty(const ccd_list_t *head); | |
96 | ||
97 | /** | |
98 | * Appends item to end of the list l. | |
99 | */ | |
100 | _ccd_inline void ccdListAppend(ccd_list_t *l, ccd_list_t *item); | |
101 | ||
102 | /** | |
103 | * Removes item from list. | |
104 | */ | |
105 | _ccd_inline void ccdListDel(ccd_list_t *item); | |
106 | ||
107 | ||
108 | ||
109 | /// | |
110 | /// INLINES: | |
111 | /// | |
112 | ||
113 | _ccd_inline void ccdListInit(ccd_list_t *l) | |
114 | { | |
115 | l->next = l; | |
116 | l->prev = l; | |
117 | } | |
118 | ||
119 | _ccd_inline ccd_list_t *ccdListNext(ccd_list_t *l) | |
120 | { | |
121 | return l->next; | |
122 | } | |
123 | ||
124 | _ccd_inline ccd_list_t *ccdListPrev(ccd_list_t *l) | |
125 | { | |
126 | return l->prev; | |
127 | } | |
128 | ||
129 | _ccd_inline int ccdListEmpty(const ccd_list_t *head) | |
130 | { | |
131 | return head->next == head; | |
132 | } | |
133 | ||
134 | _ccd_inline void ccdListAppend(ccd_list_t *l, ccd_list_t *new) | |
135 | { | |
136 | new->prev = l->prev; | |
137 | new->next = l; | |
138 | l->prev->next = new; | |
139 | l->prev = new; | |
140 | } | |
141 | ||
142 | _ccd_inline void ccdListDel(ccd_list_t *item) | |
143 | { | |
144 | item->next->prev = item->prev; | |
145 | item->prev->next = item->next; | |
146 | item->next = item; | |
147 | item->prev = item; | |
148 | } | |
149 | ||
150 | #ifdef __cplusplus | |
151 | } /* extern "C" */ | |
152 | #endif /* __cplusplus */ | |
153 | ||
154 | #endif /* __CCD_LIST_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_POLYTOPE_H__ | |
18 | #define __CCD_POLYTOPE_H__ | |
19 | ||
20 | #include <stdlib.h> | |
21 | #include <stdio.h> | |
22 | #include <ccd/support.h> | |
23 | #include <ccd/list.h> | |
24 | ||
25 | #ifdef __cplusplus | |
26 | extern "C" { | |
27 | #endif /* __cplusplus */ | |
28 | ||
29 | #define CCD_PT_VERTEX 1 | |
30 | #define CCD_PT_EDGE 2 | |
31 | #define CCD_PT_FACE 3 | |
32 | ||
33 | ||
34 | #define __CCD_PT_EL \ | |
35 | int type; /*! type of element */ \ | |
36 | ccd_real_t dist; /*! distance from origin */ \ | |
37 | ccd_vec3_t witness; /*! witness point of projection of origin */ \ | |
38 | ccd_list_t list; /*! list of elements of same type */ | |
39 | ||
40 | /** | |
41 | * General polytope element. | |
42 | * Could be vertex, edge or triangle. | |
43 | */ | |
44 | struct _ccd_pt_el_t { | |
45 | __CCD_PT_EL | |
46 | }; | |
47 | typedef struct _ccd_pt_el_t ccd_pt_el_t; | |
48 | ||
49 | struct _ccd_pt_edge_t; | |
50 | struct _ccd_pt_face_t; | |
51 | ||
52 | /** | |
53 | * Polytope's vertex. | |
54 | */ | |
55 | struct _ccd_pt_vertex_t { | |
56 | __CCD_PT_EL | |
57 | ||
58 | int id; | |
59 | ccd_support_t v; | |
60 | ccd_list_t edges; //!< List of edges | |
61 | }; | |
62 | typedef struct _ccd_pt_vertex_t ccd_pt_vertex_t; | |
63 | ||
64 | /** | |
65 | * Polytope's edge. | |
66 | */ | |
67 | struct _ccd_pt_edge_t { | |
68 | __CCD_PT_EL | |
69 | ||
70 | ccd_pt_vertex_t *vertex[2]; //!< Reference to vertices | |
71 | struct _ccd_pt_face_t *faces[2]; //!< Reference to faces | |
72 | ||
73 | ccd_list_t vertex_list[2]; //!< List items in vertices' lists | |
74 | }; | |
75 | typedef struct _ccd_pt_edge_t ccd_pt_edge_t; | |
76 | ||
77 | /** | |
78 | * Polytope's triangle faces. | |
79 | */ | |
80 | struct _ccd_pt_face_t { | |
81 | __CCD_PT_EL | |
82 | ||
83 | ccd_pt_edge_t *edge[3]; //!< Reference to surrounding edges | |
84 | }; | |
85 | typedef struct _ccd_pt_face_t ccd_pt_face_t; | |
86 | ||
87 | ||
88 | /** | |
89 | * Struct containing polytope. | |
90 | */ | |
91 | struct _ccd_pt_t { | |
92 | ccd_list_t vertices; //!< List of vertices | |
93 | ccd_list_t edges; //!< List of edges | |
94 | ccd_list_t faces; //!< List of faces | |
95 | ||
96 | ccd_pt_el_t *nearest; | |
97 | ccd_real_t nearest_dist; | |
98 | int nearest_type; | |
99 | }; | |
100 | typedef struct _ccd_pt_t ccd_pt_t; | |
101 | ||
102 | ||
103 | void ccdPtInit(ccd_pt_t *pt); | |
104 | void ccdPtDestroy(ccd_pt_t *pt); | |
105 | ||
106 | /** | |
107 | * Returns vertices surrounding given triangle face. | |
108 | */ | |
109 | _ccd_inline void ccdPtFaceVec3(const ccd_pt_face_t *face, | |
110 | ccd_vec3_t **a, | |
111 | ccd_vec3_t **b, | |
112 | ccd_vec3_t **c); | |
113 | _ccd_inline void ccdPtFaceVertices(const ccd_pt_face_t *face, | |
114 | ccd_pt_vertex_t **a, | |
115 | ccd_pt_vertex_t **b, | |
116 | ccd_pt_vertex_t **c); | |
117 | _ccd_inline void ccdPtFaceEdges(const ccd_pt_face_t *f, | |
118 | ccd_pt_edge_t **a, | |
119 | ccd_pt_edge_t **b, | |
120 | ccd_pt_edge_t **c); | |
121 | ||
122 | _ccd_inline void ccdPtEdgeVec3(const ccd_pt_edge_t *e, | |
123 | ccd_vec3_t **a, | |
124 | ccd_vec3_t **b); | |
125 | _ccd_inline void ccdPtEdgeVertices(const ccd_pt_edge_t *e, | |
126 | ccd_pt_vertex_t **a, | |
127 | ccd_pt_vertex_t **b); | |
128 | _ccd_inline void ccdPtEdgeFaces(const ccd_pt_edge_t *e, | |
129 | ccd_pt_face_t **f1, | |
130 | ccd_pt_face_t **f2); | |
131 | ||
132 | ||
133 | /** | |
134 | * Adds vertex to polytope and returns pointer to newly created vertex. | |
135 | */ | |
136 | ccd_pt_vertex_t *ccdPtAddVertex(ccd_pt_t *pt, const ccd_support_t *v); | |
137 | _ccd_inline ccd_pt_vertex_t *ccdPtAddVertexCoords(ccd_pt_t *pt, | |
138 | ccd_real_t x, ccd_real_t y, ccd_real_t z); | |
139 | ||
140 | /** | |
141 | * Adds edge to polytope. | |
142 | */ | |
143 | ccd_pt_edge_t *ccdPtAddEdge(ccd_pt_t *pt, ccd_pt_vertex_t *v1, | |
144 | ccd_pt_vertex_t *v2); | |
145 | ||
146 | /** | |
147 | * Adds face to polytope. | |
148 | */ | |
149 | ccd_pt_face_t *ccdPtAddFace(ccd_pt_t *pt, ccd_pt_edge_t *e1, | |
150 | ccd_pt_edge_t *e2, | |
151 | ccd_pt_edge_t *e3); | |
152 | ||
153 | /** | |
154 | * Deletes vertex from polytope. | |
155 | * Returns 0 on success, -1 otherwise. | |
156 | */ | |
157 | _ccd_inline int ccdPtDelVertex(ccd_pt_t *pt, ccd_pt_vertex_t *); | |
158 | _ccd_inline int ccdPtDelEdge(ccd_pt_t *pt, ccd_pt_edge_t *); | |
159 | _ccd_inline int ccdPtDelFace(ccd_pt_t *pt, ccd_pt_face_t *); | |
160 | ||
161 | ||
162 | /** | |
163 | * Recompute distances from origin for all elements in pt. | |
164 | */ | |
165 | void ccdPtRecomputeDistances(ccd_pt_t *pt); | |
166 | ||
167 | /** | |
168 | * Returns nearest element to origin. | |
169 | */ | |
170 | ccd_pt_el_t *ccdPtNearest(ccd_pt_t *pt); | |
171 | ||
172 | ||
173 | void ccdPtDumpSVT(ccd_pt_t *pt, const char *fn); | |
174 | void ccdPtDumpSVT2(ccd_pt_t *pt, FILE *); | |
175 | ||
176 | ||
177 | /**** INLINES ****/ | |
178 | _ccd_inline ccd_pt_vertex_t *ccdPtAddVertexCoords(ccd_pt_t *pt, | |
179 | ccd_real_t x, ccd_real_t y, ccd_real_t z) | |
180 | { | |
181 | ccd_support_t s; | |
182 | ccdVec3Set(&s.v, x, y, z); | |
183 | return ccdPtAddVertex(pt, &s); | |
184 | } | |
185 | ||
186 | _ccd_inline int ccdPtDelVertex(ccd_pt_t *pt, ccd_pt_vertex_t *v) | |
187 | { | |
188 | // test if any edge is connected to this vertex | |
189 | if (!ccdListEmpty(&v->edges)) | |
190 | return -1; | |
191 | ||
192 | // delete vertex from main list | |
193 | ccdListDel(&v->list); | |
194 | ||
195 | if ((void *)pt->nearest == (void *)v){ | |
196 | pt->nearest = NULL; | |
197 | } | |
198 | ||
199 | free(v); | |
200 | return 0; | |
201 | } | |
202 | ||
203 | _ccd_inline int ccdPtDelEdge(ccd_pt_t *pt, ccd_pt_edge_t *e) | |
204 | { | |
205 | // text if any face is connected to this edge (faces[] is always | |
206 | // aligned to lower indices) | |
207 | if (e->faces[0] != NULL) | |
208 | return -1; | |
209 | ||
210 | // disconnect edge from lists of edges in vertex struct | |
211 | ccdListDel(&e->vertex_list[0]); | |
212 | ccdListDel(&e->vertex_list[1]); | |
213 | ||
214 | // disconnect edge from main list | |
215 | ccdListDel(&e->list); | |
216 | ||
217 | if ((void *)pt->nearest == (void *)e){ | |
218 | pt->nearest = NULL; | |
219 | } | |
220 | ||
221 | free(e); | |
222 | return 0; | |
223 | } | |
224 | ||
225 | _ccd_inline int ccdPtDelFace(ccd_pt_t *pt, ccd_pt_face_t *f) | |
226 | { | |
227 | ccd_pt_edge_t *e; | |
228 | size_t i; | |
229 | ||
230 | // remove face from edges' recerence lists | |
231 | for (i = 0; i < 3; i++){ | |
232 | e = f->edge[i]; | |
233 | if (e->faces[0] == f){ | |
234 | e->faces[0] = e->faces[1]; | |
235 | } | |
236 | e->faces[1] = NULL; | |
237 | } | |
238 | ||
239 | // remove face from list of all faces | |
240 | ccdListDel(&f->list); | |
241 | ||
242 | if ((void *)pt->nearest == (void *)f){ | |
243 | pt->nearest = NULL; | |
244 | } | |
245 | ||
246 | free(f); | |
247 | return 0; | |
248 | } | |
249 | ||
250 | _ccd_inline void ccdPtFaceVec3(const ccd_pt_face_t *face, | |
251 | ccd_vec3_t **a, | |
252 | ccd_vec3_t **b, | |
253 | ccd_vec3_t **c) | |
254 | { | |
255 | *a = &face->edge[0]->vertex[0]->v.v; | |
256 | *b = &face->edge[0]->vertex[1]->v.v; | |
257 | ||
258 | if (face->edge[1]->vertex[0] != face->edge[0]->vertex[0] | |
259 | && face->edge[1]->vertex[0] != face->edge[0]->vertex[1]){ | |
260 | *c = &face->edge[1]->vertex[0]->v.v; | |
261 | }else{ | |
262 | *c = &face->edge[1]->vertex[1]->v.v; | |
263 | } | |
264 | } | |
265 | ||
266 | _ccd_inline void ccdPtFaceVertices(const ccd_pt_face_t *face, | |
267 | ccd_pt_vertex_t **a, | |
268 | ccd_pt_vertex_t **b, | |
269 | ccd_pt_vertex_t **c) | |
270 | { | |
271 | *a = face->edge[0]->vertex[0]; | |
272 | *b = face->edge[0]->vertex[1]; | |
273 | ||
274 | if (face->edge[1]->vertex[0] != face->edge[0]->vertex[0] | |
275 | && face->edge[1]->vertex[0] != face->edge[0]->vertex[1]){ | |
276 | *c = face->edge[1]->vertex[0]; | |
277 | }else{ | |
278 | *c = face->edge[1]->vertex[1]; | |
279 | } | |
280 | } | |
281 | ||
282 | _ccd_inline void ccdPtFaceEdges(const ccd_pt_face_t *f, | |
283 | ccd_pt_edge_t **a, | |
284 | ccd_pt_edge_t **b, | |
285 | ccd_pt_edge_t **c) | |
286 | { | |
287 | *a = f->edge[0]; | |
288 | *b = f->edge[1]; | |
289 | *c = f->edge[2]; | |
290 | } | |
291 | ||
292 | _ccd_inline void ccdPtEdgeVec3(const ccd_pt_edge_t *e, | |
293 | ccd_vec3_t **a, | |
294 | ccd_vec3_t **b) | |
295 | { | |
296 | *a = &e->vertex[0]->v.v; | |
297 | *b = &e->vertex[1]->v.v; | |
298 | } | |
299 | ||
300 | _ccd_inline void ccdPtEdgeVertices(const ccd_pt_edge_t *e, | |
301 | ccd_pt_vertex_t **a, | |
302 | ccd_pt_vertex_t **b) | |
303 | { | |
304 | *a = e->vertex[0]; | |
305 | *b = e->vertex[1]; | |
306 | } | |
307 | ||
308 | _ccd_inline void ccdPtEdgeFaces(const ccd_pt_edge_t *e, | |
309 | ccd_pt_face_t **f1, | |
310 | ccd_pt_face_t **f2) | |
311 | { | |
312 | *f1 = e->faces[0]; | |
313 | *f2 = e->faces[1]; | |
314 | } | |
315 | ||
316 | ||
317 | #ifdef __cplusplus | |
318 | } /* extern "C" */ | |
319 | #endif /* __cplusplus */ | |
320 | ||
321 | #endif /* __CCD_POLYTOPE_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_QUAT_H__ | |
18 | #define __CCD_QUAT_H__ | |
19 | ||
20 | #include <ccd/compiler.h> | |
21 | #include <ccd/vec3.h> | |
22 | ||
23 | #ifdef __cplusplus | |
24 | extern "C" { | |
25 | #endif /* __cplusplus */ | |
26 | ||
27 | struct _ccd_quat_t { | |
28 | ccd_real_t q[4]; //!< x, y, z, w | |
29 | }; | |
30 | typedef struct _ccd_quat_t ccd_quat_t; | |
31 | ||
32 | #define CCD_QUAT(name, x, y, z, w) \ | |
33 | ccd_quat_t name = { {x, y, z, w} } | |
34 | ||
35 | _ccd_inline ccd_real_t ccdQuatLen2(const ccd_quat_t *q); | |
36 | _ccd_inline ccd_real_t ccdQuatLen(const ccd_quat_t *q); | |
37 | ||
38 | _ccd_inline void ccdQuatSet(ccd_quat_t *q, ccd_real_t x, ccd_real_t y, ccd_real_t z, ccd_real_t w); | |
39 | _ccd_inline void ccdQuatCopy(ccd_quat_t *dest, const ccd_quat_t *src); | |
40 | ||
41 | _ccd_inline int ccdQuatNormalize(ccd_quat_t *q); | |
42 | ||
43 | _ccd_inline void ccdQuatSetAngleAxis(ccd_quat_t *q, | |
44 | ccd_real_t angle, const ccd_vec3_t *axis); | |
45 | ||
46 | _ccd_inline void ccdQuatScale(ccd_quat_t *q, ccd_real_t k); | |
47 | ||
48 | /** | |
49 | * q = q * q2 | |
50 | */ | |
51 | _ccd_inline void ccdQuatMul(ccd_quat_t *q, const ccd_quat_t *q2); | |
52 | ||
53 | /** | |
54 | * q = a * b | |
55 | */ | |
56 | _ccd_inline void ccdQuatMul2(ccd_quat_t *q, | |
57 | const ccd_quat_t *a, const ccd_quat_t *b); | |
58 | ||
59 | /** | |
60 | * Inverts quaternion. | |
61 | * Returns 0 on success. | |
62 | */ | |
63 | _ccd_inline int ccdQuatInvert(ccd_quat_t *q); | |
64 | _ccd_inline int ccdQuatInvert2(ccd_quat_t *dest, const ccd_quat_t *src); | |
65 | ||
66 | ||
67 | /** | |
68 | * Rotate vector v by quaternion q. | |
69 | */ | |
70 | _ccd_inline void ccdQuatRotVec(ccd_vec3_t *v, const ccd_quat_t *q); | |
71 | ||
72 | ||
73 | /**** INLINES ****/ | |
74 | _ccd_inline ccd_real_t ccdQuatLen2(const ccd_quat_t *q) | |
75 | { | |
76 | ccd_real_t len; | |
77 | ||
78 | len = q->q[0] * q->q[0]; | |
79 | len += q->q[1] * q->q[1]; | |
80 | len += q->q[2] * q->q[2]; | |
81 | len += q->q[3] * q->q[3]; | |
82 | ||
83 | return len; | |
84 | } | |
85 | ||
86 | _ccd_inline ccd_real_t ccdQuatLen(const ccd_quat_t *q) | |
87 | { | |
88 | return CCD_SQRT(ccdQuatLen2(q)); | |
89 | } | |
90 | ||
91 | _ccd_inline void ccdQuatSet(ccd_quat_t *q, ccd_real_t x, ccd_real_t y, ccd_real_t z, ccd_real_t w) | |
92 | { | |
93 | q->q[0] = x; | |
94 | q->q[1] = y; | |
95 | q->q[2] = z; | |
96 | q->q[3] = w; | |
97 | } | |
98 | ||
99 | _ccd_inline void ccdQuatCopy(ccd_quat_t *dest, const ccd_quat_t *src) | |
100 | { | |
101 | *dest = *src; | |
102 | } | |
103 | ||
104 | ||
105 | _ccd_inline int ccdQuatNormalize(ccd_quat_t *q) | |
106 | { | |
107 | ccd_real_t len = ccdQuatLen(q); | |
108 | if (len < CCD_EPS) | |
109 | return 0; | |
110 | ||
111 | ccdQuatScale(q, CCD_ONE / len); | |
112 | return 1; | |
113 | } | |
114 | ||
115 | _ccd_inline void ccdQuatSetAngleAxis(ccd_quat_t *q, | |
116 | ccd_real_t angle, const ccd_vec3_t *axis) | |
117 | { | |
118 | ccd_real_t a, x, y, z, n, s; | |
119 | ||
120 | a = angle/2; | |
121 | x = ccdVec3X(axis); | |
122 | y = ccdVec3Y(axis); | |
123 | z = ccdVec3Z(axis); | |
124 | n = CCD_SQRT(x*x + y*y + z*z); | |
125 | ||
126 | // axis==0? (treat this the same as angle==0 with an arbitrary axis) | |
127 | if (n < CCD_EPS){ | |
128 | q->q[0] = q->q[1] = q->q[2] = CCD_ZERO; | |
129 | q->q[3] = CCD_ONE; | |
130 | }else{ | |
131 | s = sin(a)/n; | |
132 | ||
133 | q->q[3] = cos(a); | |
134 | q->q[0] = x*s; | |
135 | q->q[1] = y*s; | |
136 | q->q[2] = z*s; | |
137 | ||
138 | ccdQuatNormalize(q); | |
139 | } | |
140 | } | |
141 | ||
142 | ||
143 | _ccd_inline void ccdQuatScale(ccd_quat_t *q, ccd_real_t k) | |
144 | { | |
145 | size_t i; | |
146 | for (i = 0; i < 4; i++) | |
147 | q->q[i] *= k; | |
148 | } | |
149 | ||
150 | _ccd_inline void ccdQuatMul(ccd_quat_t *q, const ccd_quat_t *q2) | |
151 | { | |
152 | ccd_quat_t a; | |
153 | ccdQuatCopy(&a, q); | |
154 | ccdQuatMul2(q, &a, q2); | |
155 | } | |
156 | ||
157 | _ccd_inline void ccdQuatMul2(ccd_quat_t *q, | |
158 | const ccd_quat_t *a, const ccd_quat_t *b) | |
159 | { | |
160 | q->q[0] = a->q[3] * b->q[0] | |
161 | + a->q[0] * b->q[3] | |
162 | + a->q[1] * b->q[2] | |
163 | - a->q[2] * b->q[1]; | |
164 | q->q[1] = a->q[3] * b->q[1] | |
165 | + a->q[1] * b->q[3] | |
166 | - a->q[0] * b->q[2] | |
167 | + a->q[2] * b->q[0]; | |
168 | q->q[2] = a->q[3] * b->q[2] | |
169 | + a->q[2] * b->q[3] | |
170 | + a->q[0] * b->q[1] | |
171 | - a->q[1] * b->q[0]; | |
172 | q->q[3] = a->q[3] * b->q[3] | |
173 | - a->q[0] * b->q[0] | |
174 | - a->q[1] * b->q[1] | |
175 | - a->q[2] * b->q[2]; | |
176 | } | |
177 | ||
178 | _ccd_inline int ccdQuatInvert(ccd_quat_t *q) | |
179 | { | |
180 | ccd_real_t len2 = ccdQuatLen2(q); | |
181 | if (len2 < CCD_EPS) | |
182 | return -1; | |
183 | ||
184 | len2 = CCD_ONE / len2; | |
185 | ||
186 | q->q[0] = -q->q[0] * len2; | |
187 | q->q[1] = -q->q[1] * len2; | |
188 | q->q[2] = -q->q[2] * len2; | |
189 | q->q[3] = q->q[3] * len2; | |
190 | ||
191 | return 0; | |
192 | } | |
193 | _ccd_inline int ccdQuatInvert2(ccd_quat_t *dest, const ccd_quat_t *src) | |
194 | { | |
195 | ccdQuatCopy(dest, src); | |
196 | return ccdQuatInvert(dest); | |
197 | } | |
198 | ||
199 | _ccd_inline void ccdQuatRotVec(ccd_vec3_t *v, const ccd_quat_t *q) | |
200 | { | |
201 | ccd_real_t w, x, y, z, ww, xx, yy, zz, wx, wy, wz, xy, xz, yz; | |
202 | ccd_real_t vx, vy, vz; | |
203 | ||
204 | w = q->q[3]; | |
205 | x = q->q[0]; | |
206 | y = q->q[1]; | |
207 | z = q->q[2]; | |
208 | ww = w*w; | |
209 | xx = x*x; | |
210 | yy = y*y; | |
211 | zz = z*z; | |
212 | wx = w*x; | |
213 | wy = w*y; | |
214 | wz = w*z; | |
215 | xy = x*y; | |
216 | xz = x*z; | |
217 | yz = y*z; | |
218 | ||
219 | vx = ww * ccdVec3X(v) | |
220 | + xx * ccdVec3X(v) | |
221 | - yy * ccdVec3X(v) | |
222 | - zz * ccdVec3X(v) | |
223 | + 2 * ((xy - wz) * ccdVec3Y(v) | |
224 | + (xz + wy) * ccdVec3Z(v)); | |
225 | vy = ww * ccdVec3Y(v) | |
226 | - xx * ccdVec3Y(v) | |
227 | + yy * ccdVec3Y(v) | |
228 | - zz * ccdVec3Y(v) | |
229 | + 2 * ((xy + wz) * ccdVec3X(v) | |
230 | + (yz - wx) * ccdVec3Z(v)); | |
231 | vz = ww * ccdVec3Z(v) | |
232 | - xx * ccdVec3Z(v) | |
233 | - yy * ccdVec3Z(v) | |
234 | + zz * ccdVec3Z(v) | |
235 | + 2 * ((xz - wy) * ccdVec3X(v) | |
236 | + (yz + wx) * ccdVec3Y(v)); | |
237 | ccdVec3Set(v, vx, vy, vz); | |
238 | } | |
239 | ||
240 | #ifdef __cplusplus | |
241 | } /* extern "C" */ | |
242 | #endif /* __cplusplus */ | |
243 | ||
244 | #endif /* __CCD_QUAT_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_SIMPLEX_H__ | |
18 | #define __CCD_SIMPLEX_H__ | |
19 | ||
20 | #include <ccd/support.h> | |
21 | #include <ccd/compiler.h> | |
22 | ||
23 | #ifdef __cplusplus | |
24 | extern "C" { | |
25 | #endif /* __cplusplus */ | |
26 | ||
27 | struct _ccd_simplex_t { | |
28 | ccd_support_t ps[4]; | |
29 | int last; //!< index of last added point | |
30 | }; | |
31 | typedef struct _ccd_simplex_t ccd_simplex_t; | |
32 | ||
33 | ||
34 | _ccd_inline void ccdSimplexInit(ccd_simplex_t *s); | |
35 | _ccd_inline int ccdSimplexSize(const ccd_simplex_t *s); | |
36 | _ccd_inline const ccd_support_t *ccdSimplexLast(const ccd_simplex_t *s); | |
37 | _ccd_inline const ccd_support_t *ccdSimplexPoint(const ccd_simplex_t *s, int idx); | |
38 | _ccd_inline ccd_support_t *ccdSimplexPointW(ccd_simplex_t *s, int idx); | |
39 | ||
40 | _ccd_inline void ccdSimplexAdd(ccd_simplex_t *s, const ccd_support_t *v); | |
41 | _ccd_inline void ccdSimplexSet(ccd_simplex_t *s, size_t pos, const ccd_support_t *a); | |
42 | _ccd_inline void ccdSimplexSetSize(ccd_simplex_t *s, int size); | |
43 | _ccd_inline void ccdSimplexSwap(ccd_simplex_t *s, size_t pos1, size_t pos2); | |
44 | ||
45 | ||
46 | /**** INLINES ****/ | |
47 | ||
48 | _ccd_inline void ccdSimplexInit(ccd_simplex_t *s) | |
49 | { | |
50 | s->last = -1; | |
51 | } | |
52 | ||
53 | _ccd_inline int ccdSimplexSize(const ccd_simplex_t *s) | |
54 | { | |
55 | return s->last + 1; | |
56 | } | |
57 | ||
58 | _ccd_inline const ccd_support_t *ccdSimplexLast(const ccd_simplex_t *s) | |
59 | { | |
60 | return ccdSimplexPoint(s, s->last); | |
61 | } | |
62 | ||
63 | _ccd_inline const ccd_support_t *ccdSimplexPoint(const ccd_simplex_t *s, int idx) | |
64 | { | |
65 | // here is no check on boundaries | |
66 | return &s->ps[idx]; | |
67 | } | |
68 | _ccd_inline ccd_support_t *ccdSimplexPointW(ccd_simplex_t *s, int idx) | |
69 | { | |
70 | return &s->ps[idx]; | |
71 | } | |
72 | ||
73 | _ccd_inline void ccdSimplexAdd(ccd_simplex_t *s, const ccd_support_t *v) | |
74 | { | |
75 | // here is no check on boundaries in sake of speed | |
76 | ++s->last; | |
77 | ccdSupportCopy(s->ps + s->last, v); | |
78 | } | |
79 | ||
80 | _ccd_inline void ccdSimplexSet(ccd_simplex_t *s, size_t pos, const ccd_support_t *a) | |
81 | { | |
82 | ccdSupportCopy(s->ps + pos, a); | |
83 | } | |
84 | ||
85 | _ccd_inline void ccdSimplexSetSize(ccd_simplex_t *s, int size) | |
86 | { | |
87 | s->last = size - 1; | |
88 | } | |
89 | ||
90 | _ccd_inline void ccdSimplexSwap(ccd_simplex_t *s, size_t pos1, size_t pos2) | |
91 | { | |
92 | ccd_support_t supp; | |
93 | ||
94 | ccdSupportCopy(&supp, &s->ps[pos1]); | |
95 | ccdSupportCopy(&s->ps[pos1], &s->ps[pos2]); | |
96 | ccdSupportCopy(&s->ps[pos2], &supp); | |
97 | } | |
98 | ||
99 | #ifdef __cplusplus | |
100 | } /* extern "C" */ | |
101 | #endif /* __cplusplus */ | |
102 | ||
103 | #endif /* __CCD_SIMPLEX_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_SUPPORT_H__ | |
18 | #define __CCD_SUPPORT_H__ | |
19 | ||
20 | #include <ccd/compiler.h> | |
21 | #include <ccd/vec3.h> | |
22 | #include <ccd/ccd.h> | |
23 | ||
24 | #ifdef __cplusplus | |
25 | extern "C" { | |
26 | #endif /* __cplusplus */ | |
27 | ||
28 | struct _ccd_support_t { | |
29 | ccd_vec3_t v; //!< Support point in minkowski sum | |
30 | ccd_vec3_t v1; //!< Support point in obj1 | |
31 | ccd_vec3_t v2; //!< Support point in obj2 | |
32 | }; | |
33 | typedef struct _ccd_support_t ccd_support_t; | |
34 | ||
35 | _ccd_inline void ccdSupportCopy(ccd_support_t *, const ccd_support_t *s); | |
36 | ||
37 | /** | |
38 | * Computes support point of obj1 and obj2 in direction dir. | |
39 | * Support point is returned via supp. | |
40 | */ | |
41 | void __ccdSupport(const void *obj1, const void *obj2, | |
42 | const ccd_vec3_t *dir, const ccd_t *ccd, | |
43 | ccd_support_t *supp); | |
44 | ||
45 | ||
46 | /**** INLINES ****/ | |
47 | _ccd_inline void ccdSupportCopy(ccd_support_t *d, const ccd_support_t *s) | |
48 | { | |
49 | *d = *s; | |
50 | } | |
51 | ||
52 | #ifdef __cplusplus | |
53 | } /* extern "C" */ | |
54 | #endif /* __cplusplus */ | |
55 | ||
56 | #endif /* __CCD_SUPPORT_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010-2013 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #ifndef __CCD_VEC3_H__ | |
18 | #define __CCD_VEC3_H__ | |
19 | ||
20 | #include <math.h> | |
21 | #include <float.h> | |
22 | #include <stdlib.h> | |
23 | #include <ccd/compiler.h> | |
24 | #include <ccd/config.h> | |
25 | ||
26 | #ifdef __cplusplus | |
27 | extern "C" { | |
28 | #endif /* __cplusplus */ | |
29 | ||
30 | ||
31 | #ifndef CCD_SINGLE | |
32 | # ifndef CCD_DOUBLE | |
33 | # error You must define CCD_SINGLE or CCD_DOUBLE | |
34 | # endif /* CCD_DOUBLE */ | |
35 | #endif /* CCD_SINGLE */ | |
36 | ||
37 | #ifdef WIN32 | |
38 | # define CCD_FMIN(x, y) ((x) < (y) ? (x) : (y)) | |
39 | #endif /* WIN32 */ | |
40 | ||
41 | #ifdef CCD_SINGLE | |
42 | # ifdef CCD_DOUBLE | |
43 | # error You can define either CCD_SINGLE or CCD_DOUBLE, not both! | |
44 | # endif /* CCD_DOUBLE */ | |
45 | ||
46 | typedef float ccd_real_t; | |
47 | ||
48 | //# define CCD_EPS 1E-6 | |
49 | # define CCD_EPS FLT_EPSILON | |
50 | ||
51 | # define CCD_REAL_MAX FLT_MAX | |
52 | ||
53 | # define CCD_REAL(x) (x ## f) /*!< form a constant */ | |
54 | # define CCD_SQRT(x) (sqrtf(x)) /*!< square root */ | |
55 | # define CCD_FABS(x) (fabsf(x)) /*!< absolute value */ | |
56 | # define CCD_FMAX(x, y) (fmaxf((x), (y))) /*!< maximum of two floats */ | |
57 | ||
58 | # ifndef CCD_FMIN | |
59 | # define CCD_FMIN(x, y) (fminf((x), (y))) /*!< minimum of two floats */ | |
60 | # endif /* CCD_FMIN */ | |
61 | ||
62 | #endif /* CCD_SINGLE */ | |
63 | ||
64 | #ifdef CCD_DOUBLE | |
65 | typedef double ccd_real_t; | |
66 | ||
67 | //# define CCD_EPS 1E-10 | |
68 | # define CCD_EPS DBL_EPSILON | |
69 | ||
70 | # define CCD_REAL_MAX DBL_MAX | |
71 | ||
72 | # define CCD_REAL(x) (x) /*!< form a constant */ | |
73 | # define CCD_SQRT(x) (sqrt(x)) /*!< square root */ | |
74 | # define CCD_FABS(x) (fabs(x)) /*!< absolute value */ | |
75 | # define CCD_FMAX(x, y) (fmax((x), (y))) /*!< maximum of two floats */ | |
76 | ||
77 | # ifndef CCD_FMIN | |
78 | # define CCD_FMIN(x, y) (fmin((x), (y))) /*!< minimum of two floats */ | |
79 | # endif /* CCD_FMIN */ | |
80 | ||
81 | #endif /* CCD_DOUBLE */ | |
82 | ||
83 | #define CCD_ONE CCD_REAL(1.) | |
84 | #define CCD_ZERO CCD_REAL(0.) | |
85 | ||
86 | struct _ccd_vec3_t { | |
87 | ccd_real_t v[3]; | |
88 | }; | |
89 | typedef struct _ccd_vec3_t ccd_vec3_t; | |
90 | ||
91 | ||
92 | /** | |
93 | * Holds origin (0,0,0) - this variable is meant to be read-only! | |
94 | */ | |
95 | extern ccd_vec3_t *ccd_vec3_origin; | |
96 | ||
97 | /** | |
98 | * Array of points uniformly distributed on unit sphere. | |
99 | */ | |
100 | extern ccd_vec3_t *ccd_points_on_sphere; | |
101 | extern size_t ccd_points_on_sphere_len; | |
102 | ||
103 | /** Returns sign of value. */ | |
104 | _ccd_inline int ccdSign(ccd_real_t val); | |
105 | /** Returns true if val is zero. **/ | |
106 | _ccd_inline int ccdIsZero(ccd_real_t val); | |
107 | /** Returns true if a and b equal. **/ | |
108 | _ccd_inline int ccdEq(ccd_real_t a, ccd_real_t b); | |
109 | ||
110 | ||
111 | #define CCD_VEC3_STATIC(x, y, z) \ | |
112 | { { (x), (y), (z) } } | |
113 | ||
114 | #define CCD_VEC3(name, x, y, z) \ | |
115 | ccd_vec3_t name = CCD_VEC3_STATIC((x), (y), (z)) | |
116 | ||
117 | _ccd_inline ccd_real_t ccdVec3X(const ccd_vec3_t *v); | |
118 | _ccd_inline ccd_real_t ccdVec3Y(const ccd_vec3_t *v); | |
119 | _ccd_inline ccd_real_t ccdVec3Z(const ccd_vec3_t *v); | |
120 | ||
121 | /** | |
122 | * Returns true if a and b equal. | |
123 | */ | |
124 | _ccd_inline int ccdVec3Eq(const ccd_vec3_t *a, const ccd_vec3_t *b); | |
125 | ||
126 | /** | |
127 | * Returns squared length of vector. | |
128 | */ | |
129 | _ccd_inline ccd_real_t ccdVec3Len2(const ccd_vec3_t *v); | |
130 | ||
131 | /** | |
132 | * Returns distance between a and b. | |
133 | */ | |
134 | _ccd_inline ccd_real_t ccdVec3Dist2(const ccd_vec3_t *a, const ccd_vec3_t *b); | |
135 | ||
136 | ||
137 | _ccd_inline void ccdVec3Set(ccd_vec3_t *v, ccd_real_t x, ccd_real_t y, ccd_real_t z); | |
138 | ||
139 | /** | |
140 | * v = w | |
141 | */ | |
142 | _ccd_inline void ccdVec3Copy(ccd_vec3_t *v, const ccd_vec3_t *w); | |
143 | ||
144 | /** | |
145 | * Substracts coordinates of vector w from vector v. v = v - w | |
146 | */ | |
147 | _ccd_inline void ccdVec3Sub(ccd_vec3_t *v, const ccd_vec3_t *w); | |
148 | ||
149 | /** | |
150 | * Adds coordinates of vector w to vector v. v = v + w | |
151 | */ | |
152 | _ccd_inline void ccdVec3Add(ccd_vec3_t *v, const ccd_vec3_t *w); | |
153 | ||
154 | /** | |
155 | * d = v - w | |
156 | */ | |
157 | _ccd_inline void ccdVec3Sub2(ccd_vec3_t *d, const ccd_vec3_t *v, const ccd_vec3_t *w); | |
158 | ||
159 | /** | |
160 | * d = d * k; | |
161 | */ | |
162 | _ccd_inline void ccdVec3Scale(ccd_vec3_t *d, ccd_real_t k); | |
163 | ||
164 | /** | |
165 | * Normalizes given vector to unit length. | |
166 | */ | |
167 | _ccd_inline void ccdVec3Normalize(ccd_vec3_t *d); | |
168 | ||
169 | ||
170 | /** | |
171 | * Dot product of two vectors. | |
172 | */ | |
173 | _ccd_inline ccd_real_t ccdVec3Dot(const ccd_vec3_t *a, const ccd_vec3_t *b); | |
174 | ||
175 | /** | |
176 | * Cross product: d = a x b. | |
177 | */ | |
178 | _ccd_inline void ccdVec3Cross(ccd_vec3_t *d, const ccd_vec3_t *a, const ccd_vec3_t *b); | |
179 | ||
180 | ||
181 | /** | |
182 | * Returns distance^2 of point P to segment ab. | |
183 | * If witness is non-NULL it is filled with coordinates of point from which | |
184 | * was computaed distance to point P. | |
185 | */ | |
186 | ccd_real_t ccdVec3PointSegmentDist2(const ccd_vec3_t *P, | |
187 | const ccd_vec3_t *a, const ccd_vec3_t *b, | |
188 | ccd_vec3_t *witness); | |
189 | ||
190 | /** | |
191 | * Returns distance^2 of point P from triangle formed by triplet a, b, c. | |
192 | * If witness vector is provided it is filled with coordinates of point | |
193 | * from which was computed distance to point P. | |
194 | */ | |
195 | ccd_real_t ccdVec3PointTriDist2(const ccd_vec3_t *P, | |
196 | const ccd_vec3_t *a, const ccd_vec3_t *b, | |
197 | const ccd_vec3_t *c, | |
198 | ccd_vec3_t *witness); | |
199 | ||
200 | ||
201 | /**** INLINES ****/ | |
202 | _ccd_inline int ccdSign(ccd_real_t val) | |
203 | { | |
204 | if (ccdIsZero(val)){ | |
205 | return 0; | |
206 | }else if (val < CCD_ZERO){ | |
207 | return -1; | |
208 | } | |
209 | return 1; | |
210 | } | |
211 | ||
212 | _ccd_inline int ccdIsZero(ccd_real_t val) | |
213 | { | |
214 | return CCD_FABS(val) < CCD_EPS; | |
215 | } | |
216 | ||
217 | _ccd_inline int ccdEq(ccd_real_t _a, ccd_real_t _b) | |
218 | { | |
219 | ccd_real_t ab; | |
220 | ccd_real_t a, b; | |
221 | ||
222 | ab = CCD_FABS(_a - _b); | |
223 | if (CCD_FABS(ab) < CCD_EPS) | |
224 | return 1; | |
225 | ||
226 | a = CCD_FABS(_a); | |
227 | b = CCD_FABS(_b); | |
228 | if (b > a){ | |
229 | return ab < CCD_EPS * b; | |
230 | }else{ | |
231 | return ab < CCD_EPS * a; | |
232 | } | |
233 | } | |
234 | ||
235 | ||
236 | _ccd_inline ccd_real_t ccdVec3X(const ccd_vec3_t *v) | |
237 | { | |
238 | return v->v[0]; | |
239 | } | |
240 | ||
241 | _ccd_inline ccd_real_t ccdVec3Y(const ccd_vec3_t *v) | |
242 | { | |
243 | return v->v[1]; | |
244 | } | |
245 | ||
246 | _ccd_inline ccd_real_t ccdVec3Z(const ccd_vec3_t *v) | |
247 | { | |
248 | return v->v[2]; | |
249 | } | |
250 | ||
251 | _ccd_inline int ccdVec3Eq(const ccd_vec3_t *a, const ccd_vec3_t *b) | |
252 | { | |
253 | return ccdEq(ccdVec3X(a), ccdVec3X(b)) | |
254 | && ccdEq(ccdVec3Y(a), ccdVec3Y(b)) | |
255 | && ccdEq(ccdVec3Z(a), ccdVec3Z(b)); | |
256 | } | |
257 | ||
258 | _ccd_inline ccd_real_t ccdVec3Len2(const ccd_vec3_t *v) | |
259 | { | |
260 | return ccdVec3Dot(v, v); | |
261 | } | |
262 | ||
263 | _ccd_inline ccd_real_t ccdVec3Dist2(const ccd_vec3_t *a, const ccd_vec3_t *b) | |
264 | { | |
265 | ccd_vec3_t ab; | |
266 | ccdVec3Sub2(&ab, a, b); | |
267 | return ccdVec3Len2(&ab); | |
268 | } | |
269 | ||
270 | _ccd_inline void ccdVec3Set(ccd_vec3_t *v, ccd_real_t x, ccd_real_t y, ccd_real_t z) | |
271 | { | |
272 | v->v[0] = x; | |
273 | v->v[1] = y; | |
274 | v->v[2] = z; | |
275 | } | |
276 | ||
277 | _ccd_inline void ccdVec3Copy(ccd_vec3_t *v, const ccd_vec3_t *w) | |
278 | { | |
279 | *v = *w; | |
280 | } | |
281 | ||
282 | _ccd_inline void ccdVec3Sub(ccd_vec3_t *v, const ccd_vec3_t *w) | |
283 | { | |
284 | v->v[0] -= w->v[0]; | |
285 | v->v[1] -= w->v[1]; | |
286 | v->v[2] -= w->v[2]; | |
287 | } | |
288 | _ccd_inline void ccdVec3Sub2(ccd_vec3_t *d, const ccd_vec3_t *v, const ccd_vec3_t *w) | |
289 | { | |
290 | d->v[0] = v->v[0] - w->v[0]; | |
291 | d->v[1] = v->v[1] - w->v[1]; | |
292 | d->v[2] = v->v[2] - w->v[2]; | |
293 | } | |
294 | ||
295 | _ccd_inline void ccdVec3Add(ccd_vec3_t *v, const ccd_vec3_t *w) | |
296 | { | |
297 | v->v[0] += w->v[0]; | |
298 | v->v[1] += w->v[1]; | |
299 | v->v[2] += w->v[2]; | |
300 | } | |
301 | ||
302 | _ccd_inline void ccdVec3Scale(ccd_vec3_t *d, ccd_real_t k) | |
303 | { | |
304 | d->v[0] *= k; | |
305 | d->v[1] *= k; | |
306 | d->v[2] *= k; | |
307 | } | |
308 | ||
309 | _ccd_inline void ccdVec3Normalize(ccd_vec3_t *d) | |
310 | { | |
311 | ccd_real_t k = CCD_ONE / CCD_SQRT(ccdVec3Len2(d)); | |
312 | ccdVec3Scale(d, k); | |
313 | } | |
314 | ||
315 | _ccd_inline ccd_real_t ccdVec3Dot(const ccd_vec3_t *a, const ccd_vec3_t *b) | |
316 | { | |
317 | ccd_real_t dot; | |
318 | ||
319 | dot = a->v[0] * b->v[0]; | |
320 | dot += a->v[1] * b->v[1]; | |
321 | dot += a->v[2] * b->v[2]; | |
322 | return dot; | |
323 | } | |
324 | ||
325 | _ccd_inline void ccdVec3Cross(ccd_vec3_t *d, const ccd_vec3_t *a, const ccd_vec3_t *b) | |
326 | { | |
327 | d->v[0] = (a->v[1] * b->v[2]) - (a->v[2] * b->v[1]); | |
328 | d->v[1] = (a->v[2] * b->v[0]) - (a->v[0] * b->v[2]); | |
329 | d->v[2] = (a->v[0] * b->v[1]) - (a->v[1] * b->v[0]); | |
330 | } | |
331 | ||
332 | #ifdef __cplusplus | |
333 | } /* extern "C" */ | |
334 | #endif /* __cplusplus */ | |
335 | ||
336 | #endif /* __CCD_VEC3_H__ */ |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2012 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #include <stdio.h> | |
18 | #include <float.h> | |
19 | #include <ccd/ccd.h> | |
20 | #include <ccd/vec3.h> | |
21 | #include <ccd/simplex.h> | |
22 | #include <ccd/polytope.h> | |
23 | #include <ccd/alloc.h> | |
24 | #include <ccd/dbg.h> | |
25 | ||
26 | ||
27 | /** Performs GJK algorithm. Returns 0 if intersection was found and simplex | |
28 | * is filled with resulting polytope. */ | |
29 | static int __ccdGJK(const void *obj1, const void *obj2, | |
30 | const ccd_t *ccd, ccd_simplex_t *simplex); | |
31 | ||
32 | /** Performs GJK+EPA algorithm. Returns 0 if intersection was found and | |
33 | * pt is filled with resulting polytope and nearest with pointer to | |
34 | * nearest element (vertex, edge, face) of polytope to origin. */ | |
35 | static int __ccdGJKEPA(const void *obj1, const void *obj2, | |
36 | const ccd_t *ccd, | |
37 | ccd_pt_t *pt, ccd_pt_el_t **nearest); | |
38 | ||
39 | ||
40 | /** Returns true if simplex contains origin. | |
41 | * This function also alteres simplex and dir according to further | |
42 | * processing of GJK algorithm. */ | |
43 | static int doSimplex(ccd_simplex_t *simplex, ccd_vec3_t *dir); | |
44 | static int doSimplex2(ccd_simplex_t *simplex, ccd_vec3_t *dir); | |
45 | static int doSimplex3(ccd_simplex_t *simplex, ccd_vec3_t *dir); | |
46 | static int doSimplex4(ccd_simplex_t *simplex, ccd_vec3_t *dir); | |
47 | ||
48 | /** d = a x b x c */ | |
49 | _ccd_inline void tripleCross(const ccd_vec3_t *a, const ccd_vec3_t *b, | |
50 | const ccd_vec3_t *c, ccd_vec3_t *d); | |
51 | ||
52 | ||
53 | /** Transforms simplex to polytope. It is assumed that simplex has 4 | |
54 | * vertices. */ | |
55 | static int simplexToPolytope4(const void *obj1, const void *obj2, | |
56 | const ccd_t *ccd, | |
57 | ccd_simplex_t *simplex, | |
58 | ccd_pt_t *pt, ccd_pt_el_t **nearest); | |
59 | ||
60 | /** Transforms simplex to polytope, three vertices required */ | |
61 | static int simplexToPolytope3(const void *obj1, const void *obj2, | |
62 | const ccd_t *ccd, | |
63 | const ccd_simplex_t *simplex, | |
64 | ccd_pt_t *pt, ccd_pt_el_t **nearest); | |
65 | ||
66 | /** Transforms simplex to polytope, two vertices required */ | |
67 | static int simplexToPolytope2(const void *obj1, const void *obj2, | |
68 | const ccd_t *ccd, | |
69 | const ccd_simplex_t *simplex, | |
70 | ccd_pt_t *pt, ccd_pt_el_t **nearest); | |
71 | ||
72 | /** Expands polytope using new vertex v. | |
73 | * Return 0 on success, -2 on memory allocation failure.*/ | |
74 | static int expandPolytope(ccd_pt_t *pt, ccd_pt_el_t *el, | |
75 | const ccd_support_t *newv); | |
76 | ||
77 | /** Finds next support point (at stores it in out argument). | |
78 | * Returns 0 on success, -1 otherwise */ | |
79 | static int nextSupport(const void *obj1, const void *obj2, const ccd_t *ccd, | |
80 | const ccd_pt_el_t *el, | |
81 | ccd_support_t *out); | |
82 | ||
83 | ||
84 | ||
85 | void ccdFirstDirDefault(const void *o1, const void *o2, ccd_vec3_t *dir) | |
86 | { | |
87 | ccdVec3Set(dir, CCD_ONE, CCD_ZERO, CCD_ZERO); | |
88 | } | |
89 | ||
90 | int ccdGJKIntersect(const void *obj1, const void *obj2, const ccd_t *ccd) | |
91 | { | |
92 | ccd_simplex_t simplex; | |
93 | return __ccdGJK(obj1, obj2, ccd, &simplex) == 0; | |
94 | } | |
95 | ||
96 | int ccdGJKSeparate(const void *obj1, const void *obj2, const ccd_t *ccd, | |
97 | ccd_vec3_t *sep) | |
98 | { | |
99 | ccd_pt_t polytope; | |
100 | ccd_pt_el_t *nearest; | |
101 | int ret; | |
102 | ||
103 | ccdPtInit(&polytope); | |
104 | ||
105 | ret = __ccdGJKEPA(obj1, obj2, ccd, &polytope, &nearest); | |
106 | ||
107 | // set separation vector | |
108 | if (nearest) | |
109 | ccdVec3Copy(sep, &nearest->witness); | |
110 | ||
111 | ccdPtDestroy(&polytope); | |
112 | ||
113 | return ret; | |
114 | } | |
115 | ||
116 | ||
117 | static int penEPAPosCmp(const void *a, const void *b) | |
118 | { | |
119 | ccd_pt_vertex_t *v1, *v2; | |
120 | v1 = *(ccd_pt_vertex_t **)a; | |
121 | v2 = *(ccd_pt_vertex_t **)b; | |
122 | ||
123 | if (ccdEq(v1->dist, v2->dist)){ | |
124 | return 0; | |
125 | }else if (v1->dist < v2->dist){ | |
126 | return -1; | |
127 | }else{ | |
128 | return 1; | |
129 | } | |
130 | } | |
131 | ||
132 | static int penEPAPos(const ccd_pt_t *pt, const ccd_pt_el_t *nearest, | |
133 | ccd_vec3_t *pos) | |
134 | { | |
135 | ccd_pt_vertex_t *v; | |
136 | ccd_pt_vertex_t **vs; | |
137 | size_t i, len; | |
138 | ccd_real_t scale; | |
139 | ||
140 | // compute median | |
141 | len = 0; | |
142 | ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ | |
143 | len++; | |
144 | } | |
145 | ||
146 | vs = CCD_ALLOC_ARR(ccd_pt_vertex_t *, len); | |
147 | if (vs == NULL) | |
148 | return -1; | |
149 | ||
150 | i = 0; | |
151 | ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ | |
152 | vs[i++] = v; | |
153 | } | |
154 | ||
155 | qsort(vs, len, sizeof(ccd_pt_vertex_t *), penEPAPosCmp); | |
156 | ||
157 | ccdVec3Set(pos, CCD_ZERO, CCD_ZERO, CCD_ZERO); | |
158 | scale = CCD_ZERO; | |
159 | if (len % 2 == 1) | |
160 | len++; | |
161 | ||
162 | for (i = 0; i < len / 2; i++){ | |
163 | ccdVec3Add(pos, &vs[i]->v.v1); | |
164 | ccdVec3Add(pos, &vs[i]->v.v2); | |
165 | scale += CCD_REAL(2.); | |
166 | } | |
167 | ccdVec3Scale(pos, CCD_ONE / scale); | |
168 | ||
169 | free(vs); | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
174 | int ccdGJKPenetration(const void *obj1, const void *obj2, const ccd_t *ccd, | |
175 | ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos) | |
176 | { | |
177 | ccd_pt_t polytope; | |
178 | ccd_pt_el_t *nearest; | |
179 | int ret; | |
180 | ||
181 | ccdPtInit(&polytope); | |
182 | ||
183 | ret = __ccdGJKEPA(obj1, obj2, ccd, &polytope, &nearest); | |
184 | ||
185 | // set separation vector | |
186 | if (ret == 0 && nearest){ | |
187 | // compute depth of penetration | |
188 | *depth = CCD_SQRT(nearest->dist); | |
189 | ||
190 | // store normalized direction vector | |
191 | ccdVec3Copy(dir, &nearest->witness); | |
192 | ccdVec3Normalize(dir); | |
193 | ||
194 | // compute position | |
195 | if (penEPAPos(&polytope, nearest, pos) != 0){ | |
196 | ccdPtDestroy(&polytope); | |
197 | return -2; | |
198 | } | |
199 | } | |
200 | ||
201 | ccdPtDestroy(&polytope); | |
202 | ||
203 | return ret; | |
204 | } | |
205 | ||
206 | ||
207 | static int __ccdGJK(const void *obj1, const void *obj2, | |
208 | const ccd_t *ccd, ccd_simplex_t *simplex) | |
209 | { | |
210 | unsigned long iterations; | |
211 | ccd_vec3_t dir; // direction vector | |
212 | ccd_support_t last; // last support point | |
213 | int do_simplex_res; | |
214 | ||
215 | // initialize simplex struct | |
216 | ccdSimplexInit(simplex); | |
217 | ||
218 | // get first direction | |
219 | ccd->first_dir(obj1, obj2, &dir); | |
220 | // get first support point | |
221 | __ccdSupport(obj1, obj2, &dir, ccd, &last); | |
222 | // and add this point to simplex as last one | |
223 | ccdSimplexAdd(simplex, &last); | |
224 | ||
225 | // set up direction vector to as (O - last) which is exactly -last | |
226 | ccdVec3Copy(&dir, &last.v); | |
227 | ccdVec3Scale(&dir, -CCD_ONE); | |
228 | ||
229 | // start iterations | |
230 | for (iterations = 0UL; iterations < ccd->max_iterations; ++iterations) { | |
231 | // obtain support point | |
232 | __ccdSupport(obj1, obj2, &dir, ccd, &last); | |
233 | ||
234 | // check if farthest point in Minkowski difference in direction dir | |
235 | // isn't somewhere before origin (the test on negative dot product) | |
236 | // - because if it is, objects are not intersecting at all. | |
237 | if (ccdVec3Dot(&last.v, &dir) < CCD_ZERO){ | |
238 | return -1; // intersection not found | |
239 | } | |
240 | ||
241 | // add last support vector to simplex | |
242 | ccdSimplexAdd(simplex, &last); | |
243 | ||
244 | // if doSimplex returns 1 if objects intersect, -1 if objects don't | |
245 | // intersect and 0 if algorithm should continue | |
246 | do_simplex_res = doSimplex(simplex, &dir); | |
247 | if (do_simplex_res == 1){ | |
248 | return 0; // intersection found | |
249 | }else if (do_simplex_res == -1){ | |
250 | return -1; // intersection not found | |
251 | } | |
252 | ||
253 | if (ccdIsZero(ccdVec3Len2(&dir))){ | |
254 | return -1; // intersection not found | |
255 | } | |
256 | } | |
257 | ||
258 | // intersection wasn't found | |
259 | return -1; | |
260 | } | |
261 | ||
262 | static int __ccdGJKEPA(const void *obj1, const void *obj2, | |
263 | const ccd_t *ccd, | |
264 | ccd_pt_t *polytope, ccd_pt_el_t **nearest) | |
265 | { | |
266 | ccd_simplex_t simplex; | |
267 | ccd_support_t supp; // support point | |
268 | int ret, size; | |
269 | ||
270 | *nearest = NULL; | |
271 | ||
272 | // run GJK and obtain terminal simplex | |
273 | ret = __ccdGJK(obj1, obj2, ccd, &simplex); | |
274 | if (ret != 0) | |
275 | return -1; | |
276 | ||
277 | // transform simplex to polytope - simplex won't be used anymore | |
278 | size = ccdSimplexSize(&simplex); | |
279 | if (size == 4){ | |
280 | ret = simplexToPolytope4(obj1, obj2, ccd, &simplex, polytope, nearest); | |
281 | }else if (size == 3){ | |
282 | ret = simplexToPolytope3(obj1, obj2, ccd, &simplex, polytope, nearest); | |
283 | }else{ // size == 2 | |
284 | ret = simplexToPolytope2(obj1, obj2, ccd, &simplex, polytope, nearest); | |
285 | } | |
286 | ||
287 | if (ret == -1){ | |
288 | // touching contact | |
289 | return 0; | |
290 | }else if (ret == -2){ | |
291 | // failed memory allocation | |
292 | return -2; | |
293 | } | |
294 | ||
295 | ||
296 | while (1){ | |
297 | // get triangle nearest to origin | |
298 | *nearest = ccdPtNearest(polytope); | |
299 | ||
300 | // get next support point | |
301 | if (nextSupport(obj1, obj2, ccd, *nearest, &supp) != 0) | |
302 | break; | |
303 | ||
304 | // expand nearest triangle using new point - supp | |
305 | if (expandPolytope(polytope, *nearest, &supp) != 0) | |
306 | return -2; | |
307 | } | |
308 | ||
309 | return 0; | |
310 | } | |
311 | ||
312 | ||
313 | ||
314 | static int doSimplex2(ccd_simplex_t *simplex, ccd_vec3_t *dir) | |
315 | { | |
316 | const ccd_support_t *A, *B; | |
317 | ccd_vec3_t AB, AO, tmp; | |
318 | ccd_real_t dot; | |
319 | ||
320 | // get last added as A | |
321 | A = ccdSimplexLast(simplex); | |
322 | // get the other point | |
323 | B = ccdSimplexPoint(simplex, 0); | |
324 | // compute AB oriented segment | |
325 | ccdVec3Sub2(&AB, &B->v, &A->v); | |
326 | // compute AO vector | |
327 | ccdVec3Copy(&AO, &A->v); | |
328 | ccdVec3Scale(&AO, -CCD_ONE); | |
329 | ||
330 | // dot product AB . AO | |
331 | dot = ccdVec3Dot(&AB, &AO); | |
332 | ||
333 | // check if origin doesn't lie on AB segment | |
334 | ccdVec3Cross(&tmp, &AB, &AO); | |
335 | if (ccdIsZero(ccdVec3Len2(&tmp)) && dot > CCD_ZERO){ | |
336 | return 1; | |
337 | } | |
338 | ||
339 | // check if origin is in area where AB segment is | |
340 | if (ccdIsZero(dot) || dot < CCD_ZERO){ | |
341 | // origin is in outside are of A | |
342 | ccdSimplexSet(simplex, 0, A); | |
343 | ccdSimplexSetSize(simplex, 1); | |
344 | ccdVec3Copy(dir, &AO); | |
345 | }else{ | |
346 | // origin is in area where AB segment is | |
347 | ||
348 | // keep simplex untouched and set direction to | |
349 | // AB x AO x AB | |
350 | tripleCross(&AB, &AO, &AB, dir); | |
351 | } | |
352 | ||
353 | return 0; | |
354 | } | |
355 | ||
356 | static int doSimplex3(ccd_simplex_t *simplex, ccd_vec3_t *dir) | |
357 | { | |
358 | const ccd_support_t *A, *B, *C; | |
359 | ccd_vec3_t AO, AB, AC, ABC, tmp; | |
360 | ccd_real_t dot, dist; | |
361 | ||
362 | // get last added as A | |
363 | A = ccdSimplexLast(simplex); | |
364 | // get the other points | |
365 | B = ccdSimplexPoint(simplex, 1); | |
366 | C = ccdSimplexPoint(simplex, 0); | |
367 | ||
368 | // check touching contact | |
369 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL); | |
370 | if (ccdIsZero(dist)){ | |
371 | return 1; | |
372 | } | |
373 | ||
374 | // check if triangle is really triangle (has area > 0) | |
375 | // if not simplex can't be expanded and thus no itersection is found | |
376 | if (ccdVec3Eq(&A->v, &B->v) || ccdVec3Eq(&A->v, &C->v)){ | |
377 | return -1; | |
378 | } | |
379 | ||
380 | // compute AO vector | |
381 | ccdVec3Copy(&AO, &A->v); | |
382 | ccdVec3Scale(&AO, -CCD_ONE); | |
383 | ||
384 | // compute AB and AC segments and ABC vector (perpendircular to triangle) | |
385 | ccdVec3Sub2(&AB, &B->v, &A->v); | |
386 | ccdVec3Sub2(&AC, &C->v, &A->v); | |
387 | ccdVec3Cross(&ABC, &AB, &AC); | |
388 | ||
389 | ccdVec3Cross(&tmp, &ABC, &AC); | |
390 | dot = ccdVec3Dot(&tmp, &AO); | |
391 | if (ccdIsZero(dot) || dot > CCD_ZERO){ | |
392 | dot = ccdVec3Dot(&AC, &AO); | |
393 | if (ccdIsZero(dot) || dot > CCD_ZERO){ | |
394 | // C is already in place | |
395 | ccdSimplexSet(simplex, 1, A); | |
396 | ccdSimplexSetSize(simplex, 2); | |
397 | tripleCross(&AC, &AO, &AC, dir); | |
398 | }else{ | |
399 | ccd_do_simplex3_45: | |
400 | dot = ccdVec3Dot(&AB, &AO); | |
401 | if (ccdIsZero(dot) || dot > CCD_ZERO){ | |
402 | ccdSimplexSet(simplex, 0, B); | |
403 | ccdSimplexSet(simplex, 1, A); | |
404 | ccdSimplexSetSize(simplex, 2); | |
405 | tripleCross(&AB, &AO, &AB, dir); | |
406 | }else{ | |
407 | ccdSimplexSet(simplex, 0, A); | |
408 | ccdSimplexSetSize(simplex, 1); | |
409 | ccdVec3Copy(dir, &AO); | |
410 | } | |
411 | } | |
412 | }else{ | |
413 | ccdVec3Cross(&tmp, &AB, &ABC); | |
414 | dot = ccdVec3Dot(&tmp, &AO); | |
415 | if (ccdIsZero(dot) || dot > CCD_ZERO){ | |
416 | goto ccd_do_simplex3_45; | |
417 | }else{ | |
418 | dot = ccdVec3Dot(&ABC, &AO); | |
419 | if (ccdIsZero(dot) || dot > CCD_ZERO){ | |
420 | ccdVec3Copy(dir, &ABC); | |
421 | }else{ | |
422 | ccd_support_t Ctmp; | |
423 | ccdSupportCopy(&Ctmp, C); | |
424 | ccdSimplexSet(simplex, 0, B); | |
425 | ccdSimplexSet(simplex, 1, &Ctmp); | |
426 | ||
427 | ccdVec3Copy(dir, &ABC); | |
428 | ccdVec3Scale(dir, -CCD_ONE); | |
429 | } | |
430 | } | |
431 | } | |
432 | ||
433 | return 0; | |
434 | } | |
435 | ||
436 | static int doSimplex4(ccd_simplex_t *simplex, ccd_vec3_t *dir) | |
437 | { | |
438 | const ccd_support_t *A, *B, *C, *D; | |
439 | ccd_vec3_t AO, AB, AC, AD, ABC, ACD, ADB; | |
440 | int B_on_ACD, C_on_ADB, D_on_ABC; | |
441 | int AB_O, AC_O, AD_O; | |
442 | ccd_real_t dist; | |
443 | ||
444 | // get last added as A | |
445 | A = ccdSimplexLast(simplex); | |
446 | // get the other points | |
447 | B = ccdSimplexPoint(simplex, 2); | |
448 | C = ccdSimplexPoint(simplex, 1); | |
449 | D = ccdSimplexPoint(simplex, 0); | |
450 | ||
451 | // check if tetrahedron is really tetrahedron (has volume > 0) | |
452 | // if it is not simplex can't be expanded and thus no intersection is | |
453 | // found | |
454 | dist = ccdVec3PointTriDist2(&A->v, &B->v, &C->v, &D->v, NULL); | |
455 | if (ccdIsZero(dist)){ | |
456 | return -1; | |
457 | } | |
458 | ||
459 | // check if origin lies on some of tetrahedron's face - if so objects | |
460 | // intersect | |
461 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL); | |
462 | if (ccdIsZero(dist)) | |
463 | return 1; | |
464 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &C->v, &D->v, NULL); | |
465 | if (ccdIsZero(dist)) | |
466 | return 1; | |
467 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &D->v, NULL); | |
468 | if (ccdIsZero(dist)) | |
469 | return 1; | |
470 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, &B->v, &C->v, &D->v, NULL); | |
471 | if (ccdIsZero(dist)) | |
472 | return 1; | |
473 | ||
474 | // compute AO, AB, AC, AD segments and ABC, ACD, ADB normal vectors | |
475 | ccdVec3Copy(&AO, &A->v); | |
476 | ccdVec3Scale(&AO, -CCD_ONE); | |
477 | ccdVec3Sub2(&AB, &B->v, &A->v); | |
478 | ccdVec3Sub2(&AC, &C->v, &A->v); | |
479 | ccdVec3Sub2(&AD, &D->v, &A->v); | |
480 | ccdVec3Cross(&ABC, &AB, &AC); | |
481 | ccdVec3Cross(&ACD, &AC, &AD); | |
482 | ccdVec3Cross(&ADB, &AD, &AB); | |
483 | ||
484 | // side (positive or negative) of B, C, D relative to planes ACD, ADB | |
485 | // and ABC respectively | |
486 | B_on_ACD = ccdSign(ccdVec3Dot(&ACD, &AB)); | |
487 | C_on_ADB = ccdSign(ccdVec3Dot(&ADB, &AC)); | |
488 | D_on_ABC = ccdSign(ccdVec3Dot(&ABC, &AD)); | |
489 | ||
490 | // whether origin is on same side of ACD, ADB, ABC as B, C, D | |
491 | // respectively | |
492 | AB_O = ccdSign(ccdVec3Dot(&ACD, &AO)) == B_on_ACD; | |
493 | AC_O = ccdSign(ccdVec3Dot(&ADB, &AO)) == C_on_ADB; | |
494 | AD_O = ccdSign(ccdVec3Dot(&ABC, &AO)) == D_on_ABC; | |
495 | ||
496 | if (AB_O && AC_O && AD_O){ | |
497 | // origin is in tetrahedron | |
498 | return 1; | |
499 | ||
500 | // rearrange simplex to triangle and call doSimplex3() | |
501 | }else if (!AB_O){ | |
502 | // B is farthest from the origin among all of the tetrahedron's | |
503 | // points, so remove it from the list and go on with the triangle | |
504 | // case | |
505 | ||
506 | // D and C are in place | |
507 | ccdSimplexSet(simplex, 2, A); | |
508 | ccdSimplexSetSize(simplex, 3); | |
509 | }else if (!AC_O){ | |
510 | // C is farthest | |
511 | ccdSimplexSet(simplex, 1, D); | |
512 | ccdSimplexSet(simplex, 0, B); | |
513 | ccdSimplexSet(simplex, 2, A); | |
514 | ccdSimplexSetSize(simplex, 3); | |
515 | }else{ // (!AD_O) | |
516 | ccdSimplexSet(simplex, 0, C); | |
517 | ccdSimplexSet(simplex, 1, B); | |
518 | ccdSimplexSet(simplex, 2, A); | |
519 | ccdSimplexSetSize(simplex, 3); | |
520 | } | |
521 | ||
522 | return doSimplex3(simplex, dir); | |
523 | } | |
524 | ||
525 | static int doSimplex(ccd_simplex_t *simplex, ccd_vec3_t *dir) | |
526 | { | |
527 | if (ccdSimplexSize(simplex) == 2){ | |
528 | // simplex contains segment only one segment | |
529 | return doSimplex2(simplex, dir); | |
530 | }else if (ccdSimplexSize(simplex) == 3){ | |
531 | // simplex contains triangle | |
532 | return doSimplex3(simplex, dir); | |
533 | }else{ // ccdSimplexSize(simplex) == 4 | |
534 | // tetrahedron - this is the only shape which can encapsule origin | |
535 | // so doSimplex4() also contains test on it | |
536 | return doSimplex4(simplex, dir); | |
537 | } | |
538 | } | |
539 | ||
540 | ||
541 | _ccd_inline void tripleCross(const ccd_vec3_t *a, const ccd_vec3_t *b, | |
542 | const ccd_vec3_t *c, ccd_vec3_t *d) | |
543 | { | |
544 | ccd_vec3_t e; | |
545 | ccdVec3Cross(&e, a, b); | |
546 | ccdVec3Cross(d, &e, c); | |
547 | } | |
548 | ||
549 | ||
550 | ||
551 | /** Transforms simplex to polytope. It is assumed that simplex has 4 | |
552 | * vertices! */ | |
553 | static int simplexToPolytope4(const void *obj1, const void *obj2, | |
554 | const ccd_t *ccd, | |
555 | ccd_simplex_t *simplex, | |
556 | ccd_pt_t *pt, ccd_pt_el_t **nearest) | |
557 | { | |
558 | const ccd_support_t *a, *b, *c, *d; | |
559 | int use_polytope3; | |
560 | ccd_real_t dist; | |
561 | ccd_pt_vertex_t *v[4]; | |
562 | ccd_pt_edge_t *e[6]; | |
563 | size_t i; | |
564 | ||
565 | a = ccdSimplexPoint(simplex, 0); | |
566 | b = ccdSimplexPoint(simplex, 1); | |
567 | c = ccdSimplexPoint(simplex, 2); | |
568 | d = ccdSimplexPoint(simplex, 3); | |
569 | ||
570 | // check if origin lies on some of tetrahedron's face - if so use | |
571 | // simplexToPolytope3() | |
572 | use_polytope3 = 0; | |
573 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &b->v, &c->v, NULL); | |
574 | if (ccdIsZero(dist)){ | |
575 | use_polytope3 = 1; | |
576 | } | |
577 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &c->v, &d->v, NULL); | |
578 | if (ccdIsZero(dist)){ | |
579 | use_polytope3 = 1; | |
580 | ccdSimplexSet(simplex, 1, c); | |
581 | ccdSimplexSet(simplex, 2, d); | |
582 | } | |
583 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &b->v, &d->v, NULL); | |
584 | if (ccdIsZero(dist)){ | |
585 | use_polytope3 = 1; | |
586 | ccdSimplexSet(simplex, 2, d); | |
587 | } | |
588 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, &b->v, &c->v, &d->v, NULL); | |
589 | if (ccdIsZero(dist)){ | |
590 | use_polytope3 = 1; | |
591 | ccdSimplexSet(simplex, 0, b); | |
592 | ccdSimplexSet(simplex, 1, c); | |
593 | ccdSimplexSet(simplex, 2, d); | |
594 | } | |
595 | ||
596 | if (use_polytope3){ | |
597 | ccdSimplexSetSize(simplex, 3); | |
598 | return simplexToPolytope3(obj1, obj2, ccd, simplex, pt, nearest); | |
599 | } | |
600 | ||
601 | // no touching contact - simply create tetrahedron | |
602 | for (i = 0; i < 4; i++){ | |
603 | v[i] = ccdPtAddVertex(pt, ccdSimplexPoint(simplex, i)); | |
604 | } | |
605 | ||
606 | e[0] = ccdPtAddEdge(pt, v[0], v[1]); | |
607 | e[1] = ccdPtAddEdge(pt, v[1], v[2]); | |
608 | e[2] = ccdPtAddEdge(pt, v[2], v[0]); | |
609 | e[3] = ccdPtAddEdge(pt, v[3], v[0]); | |
610 | e[4] = ccdPtAddEdge(pt, v[3], v[1]); | |
611 | e[5] = ccdPtAddEdge(pt, v[3], v[2]); | |
612 | ||
613 | // ccdPtAdd*() functions return NULL either if the memory allocation | |
614 | // failed of if any of the input pointers are NULL, so the bad | |
615 | // allocation can be checked by the last calls of ccdPtAddFace() | |
616 | // because the rest of the bad allocations eventually "bubble up" here | |
617 | if (ccdPtAddFace(pt, e[0], e[1], e[2]) == NULL | |
618 | || ccdPtAddFace(pt, e[3], e[4], e[0]) == NULL | |
619 | || ccdPtAddFace(pt, e[4], e[5], e[1]) == NULL | |
620 | || ccdPtAddFace(pt, e[5], e[3], e[2]) == NULL){ | |
621 | return -2; | |
622 | } | |
623 | ||
624 | return 0; | |
625 | } | |
626 | ||
627 | /** Transforms simplex to polytope, three vertices required */ | |
628 | static int simplexToPolytope3(const void *obj1, const void *obj2, | |
629 | const ccd_t *ccd, | |
630 | const ccd_simplex_t *simplex, | |
631 | ccd_pt_t *pt, ccd_pt_el_t **nearest) | |
632 | { | |
633 | const ccd_support_t *a, *b, *c; | |
634 | ccd_support_t d, d2; | |
635 | ccd_vec3_t ab, ac, dir; | |
636 | ccd_pt_vertex_t *v[5]; | |
637 | ccd_pt_edge_t *e[9]; | |
638 | ccd_real_t dist, dist2; | |
639 | ||
640 | *nearest = NULL; | |
641 | ||
642 | a = ccdSimplexPoint(simplex, 0); | |
643 | b = ccdSimplexPoint(simplex, 1); | |
644 | c = ccdSimplexPoint(simplex, 2); | |
645 | ||
646 | // If only one triangle left from previous GJK run origin lies on this | |
647 | // triangle. So it is necessary to expand triangle into two | |
648 | // tetrahedrons connected with base (which is exactly abc triangle). | |
649 | ||
650 | // get next support point in direction of normal of triangle | |
651 | ccdVec3Sub2(&ab, &b->v, &a->v); | |
652 | ccdVec3Sub2(&ac, &c->v, &a->v); | |
653 | ccdVec3Cross(&dir, &ab, &ac); | |
654 | __ccdSupport(obj1, obj2, &dir, ccd, &d); | |
655 | dist = ccdVec3PointTriDist2(&d.v, &a->v, &b->v, &c->v, NULL); | |
656 | ||
657 | // and second one take in opposite direction | |
658 | ccdVec3Scale(&dir, -CCD_ONE); | |
659 | __ccdSupport(obj1, obj2, &dir, ccd, &d2); | |
660 | dist2 = ccdVec3PointTriDist2(&d2.v, &a->v, &b->v, &c->v, NULL); | |
661 | ||
662 | // check if face isn't already on edge of minkowski sum and thus we | |
663 | // have touching contact | |
664 | if (ccdIsZero(dist) || ccdIsZero(dist2)){ | |
665 | v[0] = ccdPtAddVertex(pt, a); | |
666 | v[1] = ccdPtAddVertex(pt, b); | |
667 | v[2] = ccdPtAddVertex(pt, c); | |
668 | e[0] = ccdPtAddEdge(pt, v[0], v[1]); | |
669 | e[1] = ccdPtAddEdge(pt, v[1], v[2]); | |
670 | e[2] = ccdPtAddEdge(pt, v[2], v[0]); | |
671 | *nearest = (ccd_pt_el_t *)ccdPtAddFace(pt, e[0], e[1], e[2]); | |
672 | if (*nearest == NULL) | |
673 | return -2; | |
674 | ||
675 | return -1; | |
676 | } | |
677 | ||
678 | // form polyhedron | |
679 | v[0] = ccdPtAddVertex(pt, a); | |
680 | v[1] = ccdPtAddVertex(pt, b); | |
681 | v[2] = ccdPtAddVertex(pt, c); | |
682 | v[3] = ccdPtAddVertex(pt, &d); | |
683 | v[4] = ccdPtAddVertex(pt, &d2); | |
684 | ||
685 | e[0] = ccdPtAddEdge(pt, v[0], v[1]); | |
686 | e[1] = ccdPtAddEdge(pt, v[1], v[2]); | |
687 | e[2] = ccdPtAddEdge(pt, v[2], v[0]); | |
688 | ||
689 | e[3] = ccdPtAddEdge(pt, v[3], v[0]); | |
690 | e[4] = ccdPtAddEdge(pt, v[3], v[1]); | |
691 | e[5] = ccdPtAddEdge(pt, v[3], v[2]); | |
692 | ||
693 | e[6] = ccdPtAddEdge(pt, v[4], v[0]); | |
694 | e[7] = ccdPtAddEdge(pt, v[4], v[1]); | |
695 | e[8] = ccdPtAddEdge(pt, v[4], v[2]); | |
696 | ||
697 | if (ccdPtAddFace(pt, e[3], e[4], e[0]) == NULL | |
698 | || ccdPtAddFace(pt, e[4], e[5], e[1]) == NULL | |
699 | || ccdPtAddFace(pt, e[5], e[3], e[2]) == NULL | |
700 | ||
701 | || ccdPtAddFace(pt, e[6], e[7], e[0]) == NULL | |
702 | || ccdPtAddFace(pt, e[7], e[8], e[1]) == NULL | |
703 | || ccdPtAddFace(pt, e[8], e[6], e[2]) == NULL){ | |
704 | return -2; | |
705 | } | |
706 | ||
707 | return 0; | |
708 | } | |
709 | ||
710 | /** Transforms simplex to polytope, two vertices required */ | |
711 | static int simplexToPolytope2(const void *obj1, const void *obj2, | |
712 | const ccd_t *ccd, | |
713 | const ccd_simplex_t *simplex, | |
714 | ccd_pt_t *pt, ccd_pt_el_t **nearest) | |
715 | { | |
716 | const ccd_support_t *a, *b; | |
717 | ccd_vec3_t ab, ac, dir; | |
718 | ccd_support_t supp[4]; | |
719 | ccd_pt_vertex_t *v[6]; | |
720 | ccd_pt_edge_t *e[12]; | |
721 | size_t i; | |
722 | int found; | |
723 | ||
724 | a = ccdSimplexPoint(simplex, 0); | |
725 | b = ccdSimplexPoint(simplex, 1); | |
726 | ||
727 | // This situation is a bit tricky. If only one segment comes from | |
728 | // previous run of GJK - it means that either this segment is on | |
729 | // minkowski edge (and thus we have touch contact) or it it isn't and | |
730 | // therefore segment is somewhere *inside* minkowski sum and it *must* | |
731 | // be possible to fully enclose this segment with polyhedron formed by | |
732 | // at least 8 triangle faces. | |
733 | ||
734 | // get first support point (any) | |
735 | found = 0; | |
736 | for (i = 0; i < ccd_points_on_sphere_len; i++){ | |
737 | __ccdSupport(obj1, obj2, &ccd_points_on_sphere[i], ccd, &supp[0]); | |
738 | if (!ccdVec3Eq(&a->v, &supp[0].v) && !ccdVec3Eq(&b->v, &supp[0].v)){ | |
739 | found = 1; | |
740 | break; | |
741 | } | |
742 | } | |
743 | if (!found) | |
744 | goto simplexToPolytope2_touching_contact; | |
745 | ||
746 | // get second support point in opposite direction than supp[0] | |
747 | ccdVec3Copy(&dir, &supp[0].v); | |
748 | ccdVec3Scale(&dir, -CCD_ONE); | |
749 | __ccdSupport(obj1, obj2, &dir, ccd, &supp[1]); | |
750 | if (ccdVec3Eq(&a->v, &supp[1].v) || ccdVec3Eq(&b->v, &supp[1].v)) | |
751 | goto simplexToPolytope2_touching_contact; | |
752 | ||
753 | // next will be in direction of normal of triangle a,supp[0],supp[1] | |
754 | ccdVec3Sub2(&ab, &supp[0].v, &a->v); | |
755 | ccdVec3Sub2(&ac, &supp[1].v, &a->v); | |
756 | ccdVec3Cross(&dir, &ab, &ac); | |
757 | __ccdSupport(obj1, obj2, &dir, ccd, &supp[2]); | |
758 | if (ccdVec3Eq(&a->v, &supp[2].v) || ccdVec3Eq(&b->v, &supp[2].v)) | |
759 | goto simplexToPolytope2_touching_contact; | |
760 | ||
761 | // and last one will be in opposite direction | |
762 | ccdVec3Scale(&dir, -CCD_ONE); | |
763 | __ccdSupport(obj1, obj2, &dir, ccd, &supp[3]); | |
764 | if (ccdVec3Eq(&a->v, &supp[3].v) || ccdVec3Eq(&b->v, &supp[3].v)) | |
765 | goto simplexToPolytope2_touching_contact; | |
766 | ||
767 | goto simplexToPolytope2_not_touching_contact; | |
768 | simplexToPolytope2_touching_contact: | |
769 | v[0] = ccdPtAddVertex(pt, a); | |
770 | v[1] = ccdPtAddVertex(pt, b); | |
771 | *nearest = (ccd_pt_el_t *)ccdPtAddEdge(pt, v[0], v[1]); | |
772 | if (*nearest == NULL) | |
773 | return -2; | |
774 | ||
775 | return -1; | |
776 | ||
777 | simplexToPolytope2_not_touching_contact: | |
778 | // form polyhedron | |
779 | v[0] = ccdPtAddVertex(pt, a); | |
780 | v[1] = ccdPtAddVertex(pt, &supp[0]); | |
781 | v[2] = ccdPtAddVertex(pt, b); | |
782 | v[3] = ccdPtAddVertex(pt, &supp[1]); | |
783 | v[4] = ccdPtAddVertex(pt, &supp[2]); | |
784 | v[5] = ccdPtAddVertex(pt, &supp[3]); | |
785 | ||
786 | e[0] = ccdPtAddEdge(pt, v[0], v[1]); | |
787 | e[1] = ccdPtAddEdge(pt, v[1], v[2]); | |
788 | e[2] = ccdPtAddEdge(pt, v[2], v[3]); | |
789 | e[3] = ccdPtAddEdge(pt, v[3], v[0]); | |
790 | ||
791 | e[4] = ccdPtAddEdge(pt, v[4], v[0]); | |
792 | e[5] = ccdPtAddEdge(pt, v[4], v[1]); | |
793 | e[6] = ccdPtAddEdge(pt, v[4], v[2]); | |
794 | e[7] = ccdPtAddEdge(pt, v[4], v[3]); | |
795 | ||
796 | e[8] = ccdPtAddEdge(pt, v[5], v[0]); | |
797 | e[9] = ccdPtAddEdge(pt, v[5], v[1]); | |
798 | e[10] = ccdPtAddEdge(pt, v[5], v[2]); | |
799 | e[11] = ccdPtAddEdge(pt, v[5], v[3]); | |
800 | ||
801 | if (ccdPtAddFace(pt, e[4], e[5], e[0]) == NULL | |
802 | || ccdPtAddFace(pt, e[5], e[6], e[1]) == NULL | |
803 | || ccdPtAddFace(pt, e[6], e[7], e[2]) == NULL | |
804 | || ccdPtAddFace(pt, e[7], e[4], e[3]) == NULL | |
805 | ||
806 | || ccdPtAddFace(pt, e[8], e[9], e[0]) == NULL | |
807 | || ccdPtAddFace(pt, e[9], e[10], e[1]) == NULL | |
808 | || ccdPtAddFace(pt, e[10], e[11], e[2]) == NULL | |
809 | || ccdPtAddFace(pt, e[11], e[8], e[3]) == NULL){ | |
810 | return -2; | |
811 | } | |
812 | ||
813 | return 0; | |
814 | } | |
815 | ||
816 | /** Expands polytope's tri by new vertex v. Triangle tri is replaced by | |
817 | * three triangles each with one vertex in v. */ | |
818 | static int expandPolytope(ccd_pt_t *pt, ccd_pt_el_t *el, | |
819 | const ccd_support_t *newv) | |
820 | { | |
821 | ccd_pt_vertex_t *v[5]; | |
822 | ccd_pt_edge_t *e[8]; | |
823 | ccd_pt_face_t *f[2]; | |
824 | ||
825 | ||
826 | // element can be either segment or triangle | |
827 | if (el->type == CCD_PT_EDGE){ | |
828 | // In this case, segment should be replaced by new point. | |
829 | // Simpliest case is when segment stands alone and in this case | |
830 | // this segment is replaced by two other segments both connected to | |
831 | // newv. | |
832 | // Segment can be also connected to max two faces and in that case | |
833 | // each face must be replaced by two other faces. To do this | |
834 | // correctly it is necessary to have correctly ordered edges and | |
835 | // vertices which is exactly what is done in following code. | |
836 | // | |
837 | ||
838 | ccdPtEdgeVertices((const ccd_pt_edge_t *)el, &v[0], &v[2]); | |
839 | ||
840 | ccdPtEdgeFaces((ccd_pt_edge_t *)el, &f[0], &f[1]); | |
841 | ||
842 | if (f[0]){ | |
843 | ccdPtFaceEdges(f[0], &e[0], &e[1], &e[2]); | |
844 | if (e[0] == (ccd_pt_edge_t *)el){ | |
845 | e[0] = e[2]; | |
846 | }else if (e[1] == (ccd_pt_edge_t *)el){ | |
847 | e[1] = e[2]; | |
848 | } | |
849 | ccdPtEdgeVertices(e[0], &v[1], &v[3]); | |
850 | if (v[1] != v[0] && v[3] != v[0]){ | |
851 | e[2] = e[0]; | |
852 | e[0] = e[1]; | |
853 | e[1] = e[2]; | |
854 | if (v[1] == v[2]) | |
855 | v[1] = v[3]; | |
856 | }else{ | |
857 | if (v[1] == v[0]) | |
858 | v[1] = v[3]; | |
859 | } | |
860 | ||
861 | if (f[1]){ | |
862 | ccdPtFaceEdges(f[1], &e[2], &e[3], &e[4]); | |
863 | if (e[2] == (ccd_pt_edge_t *)el){ | |
864 | e[2] = e[4]; | |
865 | }else if (e[3] == (ccd_pt_edge_t *)el){ | |
866 | e[3] = e[4]; | |
867 | } | |
868 | ccdPtEdgeVertices(e[2], &v[3], &v[4]); | |
869 | if (v[3] != v[2] && v[4] != v[2]){ | |
870 | e[4] = e[2]; | |
871 | e[2] = e[3]; | |
872 | e[3] = e[4]; | |
873 | if (v[3] == v[0]) | |
874 | v[3] = v[4]; | |
875 | }else{ | |
876 | if (v[3] == v[2]) | |
877 | v[3] = v[4]; | |
878 | } | |
879 | } | |
880 | ||
881 | ||
882 | v[4] = ccdPtAddVertex(pt, newv); | |
883 | ||
884 | ccdPtDelFace(pt, f[0]); | |
885 | if (f[1]){ | |
886 | ccdPtDelFace(pt, f[1]); | |
887 | ccdPtDelEdge(pt, (ccd_pt_edge_t *)el); | |
888 | } | |
889 | ||
890 | e[4] = ccdPtAddEdge(pt, v[4], v[2]); | |
891 | e[5] = ccdPtAddEdge(pt, v[4], v[0]); | |
892 | e[6] = ccdPtAddEdge(pt, v[4], v[1]); | |
893 | if (f[1]) | |
894 | e[7] = ccdPtAddEdge(pt, v[4], v[3]); | |
895 | ||
896 | ||
897 | if (ccdPtAddFace(pt, e[1], e[4], e[6]) == NULL | |
898 | || ccdPtAddFace(pt, e[0], e[6], e[5]) == NULL){ | |
899 | return -2; | |
900 | } | |
901 | ||
902 | if (f[1]){ | |
903 | if (ccdPtAddFace(pt, e[3], e[5], e[7]) == NULL | |
904 | || ccdPtAddFace(pt, e[4], e[7], e[2]) == NULL){ | |
905 | return -2; | |
906 | } | |
907 | }else{ | |
908 | if (ccdPtAddFace(pt, e[4], e[5], (ccd_pt_edge_t *)el) == NULL) | |
909 | return -2; | |
910 | } | |
911 | } | |
912 | }else{ // el->type == CCD_PT_FACE | |
913 | // replace triangle by tetrahedron without base (base would be the | |
914 | // triangle that will be removed) | |
915 | ||
916 | // get triplet of surrounding edges and vertices of triangle face | |
917 | ccdPtFaceEdges((const ccd_pt_face_t *)el, &e[0], &e[1], &e[2]); | |
918 | ccdPtEdgeVertices(e[0], &v[0], &v[1]); | |
919 | ccdPtEdgeVertices(e[1], &v[2], &v[3]); | |
920 | ||
921 | // following code sorts edges to have e[0] between vertices 0-1, | |
922 | // e[1] between 1-2 and e[2] between 2-0 | |
923 | if (v[2] != v[1] && v[3] != v[1]){ | |
924 | // swap e[1] and e[2] | |
925 | e[3] = e[1]; | |
926 | e[1] = e[2]; | |
927 | e[2] = e[3]; | |
928 | } | |
929 | if (v[3] != v[0] && v[3] != v[1]) | |
930 | v[2] = v[3]; | |
931 | ||
932 | // remove triangle face | |
933 | ccdPtDelFace(pt, (ccd_pt_face_t *)el); | |
934 | ||
935 | // expand triangle to tetrahedron | |
936 | v[3] = ccdPtAddVertex(pt, newv); | |
937 | e[3] = ccdPtAddEdge(pt, v[3], v[0]); | |
938 | e[4] = ccdPtAddEdge(pt, v[3], v[1]); | |
939 | e[5] = ccdPtAddEdge(pt, v[3], v[2]); | |
940 | ||
941 | if (ccdPtAddFace(pt, e[3], e[4], e[0]) == NULL | |
942 | || ccdPtAddFace(pt, e[4], e[5], e[1]) == NULL | |
943 | || ccdPtAddFace(pt, e[5], e[3], e[2]) == NULL){ | |
944 | return -2; | |
945 | } | |
946 | } | |
947 | ||
948 | return 0; | |
949 | } | |
950 | ||
951 | /** Finds next support point (and stores it in out argument). | |
952 | * Returns 0 on success, -1 otherwise */ | |
953 | static int nextSupport(const void *obj1, const void *obj2, const ccd_t *ccd, | |
954 | const ccd_pt_el_t *el, | |
955 | ccd_support_t *out) | |
956 | { | |
957 | ccd_vec3_t *a, *b, *c; | |
958 | ccd_real_t dist; | |
959 | ||
960 | if (el->type == CCD_PT_VERTEX) | |
961 | return -1; | |
962 | ||
963 | // touch contact | |
964 | if (ccdIsZero(el->dist)) | |
965 | return -1; | |
966 | ||
967 | __ccdSupport(obj1, obj2, &el->witness, ccd, out); | |
968 | ||
969 | // Compute dist of support point along element witness point direction | |
970 | // so we can determine whether we expanded a polytope surrounding the | |
971 | // origin a bit. | |
972 | dist = ccdVec3Dot(&out->v, &el->witness); | |
973 | ||
974 | if (dist - el->dist < ccd->epa_tolerance) | |
975 | return -1; | |
976 | ||
977 | if (el->type == CCD_PT_EDGE){ | |
978 | // fetch end points of edge | |
979 | ccdPtEdgeVec3((ccd_pt_edge_t *)el, &a, &b); | |
980 | ||
981 | // get distance from segment | |
982 | dist = ccdVec3PointSegmentDist2(&out->v, a, b, NULL); | |
983 | }else{ // el->type == CCD_PT_FACE | |
984 | // fetch vertices of triangle face | |
985 | ccdPtFaceVec3((ccd_pt_face_t *)el, &a, &b, &c); | |
986 | ||
987 | // check if new point can significantly expand polytope | |
988 | dist = ccdVec3PointTriDist2(&out->v, a, b, c, NULL); | |
989 | } | |
990 | ||
991 | if (dist < ccd->epa_tolerance) | |
992 | return -1; | |
993 | ||
994 | return 0; | |
995 | } |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010,2011 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #include <stdlib.h> | |
18 | #include <ccd/ccd.h> | |
19 | #include <ccd/simplex.h> | |
20 | #include <ccd/dbg.h> | |
21 | ||
22 | /** Finds origin (center) of Minkowski difference (actually it can be any | |
23 | * interior point of Minkowski difference. */ | |
24 | _ccd_inline void findOrigin(const void *obj1, const void *obj2, const ccd_t *ccd, | |
25 | ccd_support_t *center); | |
26 | ||
27 | /** Discovers initial portal - that is tetrahedron that intersects with | |
28 | * origin ray (ray from center of Minkowski diff to (0,0,0). | |
29 | * | |
30 | * Returns -1 if already recognized that origin is outside Minkowski | |
31 | * portal. | |
32 | * Returns 1 if origin lies on v1 of simplex (only v0 and v1 are present | |
33 | * in simplex). | |
34 | * Returns 2 if origin lies on v0-v1 segment. | |
35 | * Returns 0 if portal was built. | |
36 | */ | |
37 | static int discoverPortal(const void *obj1, const void *obj2, | |
38 | const ccd_t *ccd, ccd_simplex_t *portal); | |
39 | ||
40 | ||
41 | /** Expands portal towards origin and determine if objects intersect. | |
42 | * Already established portal must be given as argument. | |
43 | * If intersection is found 0 is returned, -1 otherwise */ | |
44 | static int refinePortal(const void *obj1, const void *obj2, | |
45 | const ccd_t *ccd, ccd_simplex_t *portal); | |
46 | ||
47 | /** Finds penetration info by expanding provided portal. */ | |
48 | static void findPenetr(const void *obj1, const void *obj2, const ccd_t *ccd, | |
49 | ccd_simplex_t *portal, | |
50 | ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); | |
51 | ||
52 | /** Finds penetration info if origin lies on portal's v1 */ | |
53 | static void findPenetrTouch(const void *obj1, const void *obj2, const ccd_t *ccd, | |
54 | ccd_simplex_t *portal, | |
55 | ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); | |
56 | ||
57 | /** Find penetration info if origin lies on portal's segment v0-v1 */ | |
58 | static void findPenetrSegment(const void *obj1, const void *obj2, const ccd_t *ccd, | |
59 | ccd_simplex_t *portal, | |
60 | ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); | |
61 | ||
62 | /** Finds position vector from fully established portal */ | |
63 | static void findPos(const void *obj1, const void *obj2, const ccd_t *ccd, | |
64 | const ccd_simplex_t *portal, ccd_vec3_t *pos); | |
65 | ||
66 | /** Extends portal with new support point. | |
67 | * Portal must have face v1-v2-v3 arranged to face outside portal. */ | |
68 | _ccd_inline void expandPortal(ccd_simplex_t *portal, | |
69 | const ccd_support_t *v4); | |
70 | ||
71 | /** Fill dir with direction outside portal. Portal's v1-v2-v3 face must be | |
72 | * arranged in correct order! */ | |
73 | _ccd_inline void portalDir(const ccd_simplex_t *portal, ccd_vec3_t *dir); | |
74 | ||
75 | /** Returns true if portal encapsules origin (0,0,0), dir is direction of | |
76 | * v1-v2-v3 face. */ | |
77 | _ccd_inline int portalEncapsulesOrigin(const ccd_simplex_t *portal, | |
78 | const ccd_vec3_t *dir); | |
79 | ||
80 | /** Returns true if portal with new point v4 would reach specified | |
81 | * tolerance (i.e. returns true if portal can _not_ significantly expand | |
82 | * within Minkowski difference). | |
83 | * | |
84 | * v4 is candidate for new point in portal, dir is direction in which v4 | |
85 | * was obtained. */ | |
86 | _ccd_inline int portalReachTolerance(const ccd_simplex_t *portal, | |
87 | const ccd_support_t *v4, | |
88 | const ccd_vec3_t *dir, | |
89 | const ccd_t *ccd); | |
90 | ||
91 | /** Returns true if portal expanded by new point v4 could possibly contain | |
92 | * origin, dir is direction in which v4 was obtained. */ | |
93 | _ccd_inline int portalCanEncapsuleOrigin(const ccd_simplex_t *portal, | |
94 | const ccd_support_t *v4, | |
95 | const ccd_vec3_t *dir); | |
96 | ||
97 | ||
98 | int ccdMPRIntersect(const void *obj1, const void *obj2, const ccd_t *ccd) | |
99 | { | |
100 | ccd_simplex_t portal; | |
101 | int res; | |
102 | ||
103 | // Phase 1: Portal discovery - find portal that intersects with origin | |
104 | // ray (ray from center of Minkowski diff to origin of coordinates) | |
105 | res = discoverPortal(obj1, obj2, ccd, &portal); | |
106 | if (res < 0) | |
107 | return 0; | |
108 | if (res > 0) | |
109 | return 1; | |
110 | ||
111 | // Phase 2: Portal refinement | |
112 | res = refinePortal(obj1, obj2, ccd, &portal); | |
113 | return (res == 0 ? 1 : 0); | |
114 | } | |
115 | ||
116 | int ccdMPRPenetration(const void *obj1, const void *obj2, const ccd_t *ccd, | |
117 | ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos) | |
118 | { | |
119 | ccd_simplex_t portal; | |
120 | int res; | |
121 | ||
122 | // Phase 1: Portal discovery | |
123 | res = discoverPortal(obj1, obj2, ccd, &portal); | |
124 | if (res < 0){ | |
125 | // Origin isn't inside portal - no collision. | |
126 | return -1; | |
127 | ||
128 | }else if (res == 1){ | |
129 | // Touching contact on portal's v1. | |
130 | findPenetrTouch(obj1, obj2, ccd, &portal, depth, dir, pos); | |
131 | ||
132 | }else if (res == 2){ | |
133 | // Origin lies on v0-v1 segment. | |
134 | findPenetrSegment(obj1, obj2, ccd, &portal, depth, dir, pos); | |
135 | ||
136 | }else if (res == 0){ | |
137 | // Phase 2: Portal refinement | |
138 | res = refinePortal(obj1, obj2, ccd, &portal); | |
139 | if (res < 0) | |
140 | return -1; | |
141 | ||
142 | // Phase 3. Penetration info | |
143 | findPenetr(obj1, obj2, ccd, &portal, depth, dir, pos); | |
144 | } | |
145 | ||
146 | return 0; | |
147 | } | |
148 | ||
149 | ||
150 | ||
151 | _ccd_inline void findOrigin(const void *obj1, const void *obj2, const ccd_t *ccd, | |
152 | ccd_support_t *center) | |
153 | { | |
154 | ccd->center1(obj1, ¢er->v1); | |
155 | ccd->center2(obj2, ¢er->v2); | |
156 | ccdVec3Sub2(¢er->v, ¢er->v1, ¢er->v2); | |
157 | } | |
158 | ||
159 | static int discoverPortal(const void *obj1, const void *obj2, | |
160 | const ccd_t *ccd, ccd_simplex_t *portal) | |
161 | { | |
162 | ccd_vec3_t dir, va, vb; | |
163 | ccd_real_t dot; | |
164 | int cont; | |
165 | ||
166 | // vertex 0 is center of portal | |
167 | findOrigin(obj1, obj2, ccd, ccdSimplexPointW(portal, 0)); | |
168 | ccdSimplexSetSize(portal, 1); | |
169 | ||
170 | if (ccdVec3Eq(&ccdSimplexPoint(portal, 0)->v, ccd_vec3_origin)){ | |
171 | // Portal's center lies on origin (0,0,0) => we know that objects | |
172 | // intersect but we would need to know penetration info. | |
173 | // So move center little bit... | |
174 | ccdVec3Set(&va, CCD_EPS * CCD_REAL(10.), CCD_ZERO, CCD_ZERO); | |
175 | ccdVec3Add(&ccdSimplexPointW(portal, 0)->v, &va); | |
176 | } | |
177 | ||
178 | ||
179 | // vertex 1 = support in direction of origin | |
180 | ccdVec3Copy(&dir, &ccdSimplexPoint(portal, 0)->v); | |
181 | ccdVec3Scale(&dir, CCD_REAL(-1.)); | |
182 | ccdVec3Normalize(&dir); | |
183 | __ccdSupport(obj1, obj2, &dir, ccd, ccdSimplexPointW(portal, 1)); | |
184 | ccdSimplexSetSize(portal, 2); | |
185 | ||
186 | // test if origin isn't outside of v1 | |
187 | dot = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, &dir); | |
188 | if (ccdIsZero(dot) || dot < CCD_ZERO) | |
189 | return -1; | |
190 | ||
191 | ||
192 | // vertex 2 | |
193 | ccdVec3Cross(&dir, &ccdSimplexPoint(portal, 0)->v, | |
194 | &ccdSimplexPoint(portal, 1)->v); | |
195 | if (ccdIsZero(ccdVec3Len2(&dir))){ | |
196 | if (ccdVec3Eq(&ccdSimplexPoint(portal, 1)->v, ccd_vec3_origin)){ | |
197 | // origin lies on v1 | |
198 | return 1; | |
199 | }else{ | |
200 | // origin lies on v0-v1 segment | |
201 | return 2; | |
202 | } | |
203 | } | |
204 | ||
205 | ccdVec3Normalize(&dir); | |
206 | __ccdSupport(obj1, obj2, &dir, ccd, ccdSimplexPointW(portal, 2)); | |
207 | dot = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, &dir); | |
208 | if (ccdIsZero(dot) || dot < CCD_ZERO) | |
209 | return -1; | |
210 | ||
211 | ccdSimplexSetSize(portal, 3); | |
212 | ||
213 | // vertex 3 direction | |
214 | ccdVec3Sub2(&va, &ccdSimplexPoint(portal, 1)->v, | |
215 | &ccdSimplexPoint(portal, 0)->v); | |
216 | ccdVec3Sub2(&vb, &ccdSimplexPoint(portal, 2)->v, | |
217 | &ccdSimplexPoint(portal, 0)->v); | |
218 | ccdVec3Cross(&dir, &va, &vb); | |
219 | ccdVec3Normalize(&dir); | |
220 | ||
221 | // it is better to form portal faces to be oriented "outside" origin | |
222 | dot = ccdVec3Dot(&dir, &ccdSimplexPoint(portal, 0)->v); | |
223 | if (dot > CCD_ZERO){ | |
224 | ccdSimplexSwap(portal, 1, 2); | |
225 | ccdVec3Scale(&dir, CCD_REAL(-1.)); | |
226 | } | |
227 | ||
228 | while (ccdSimplexSize(portal) < 4){ | |
229 | __ccdSupport(obj1, obj2, &dir, ccd, ccdSimplexPointW(portal, 3)); | |
230 | dot = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, &dir); | |
231 | if (ccdIsZero(dot) || dot < CCD_ZERO) | |
232 | return -1; | |
233 | ||
234 | cont = 0; | |
235 | ||
236 | // test if origin is outside (v1, v0, v3) - set v2 as v3 and | |
237 | // continue | |
238 | ccdVec3Cross(&va, &ccdSimplexPoint(portal, 1)->v, | |
239 | &ccdSimplexPoint(portal, 3)->v); | |
240 | dot = ccdVec3Dot(&va, &ccdSimplexPoint(portal, 0)->v); | |
241 | if (dot < CCD_ZERO && !ccdIsZero(dot)){ | |
242 | ccdSimplexSet(portal, 2, ccdSimplexPoint(portal, 3)); | |
243 | cont = 1; | |
244 | } | |
245 | ||
246 | if (!cont){ | |
247 | // test if origin is outside (v3, v0, v2) - set v1 as v3 and | |
248 | // continue | |
249 | ccdVec3Cross(&va, &ccdSimplexPoint(portal, 3)->v, | |
250 | &ccdSimplexPoint(portal, 2)->v); | |
251 | dot = ccdVec3Dot(&va, &ccdSimplexPoint(portal, 0)->v); | |
252 | if (dot < CCD_ZERO && !ccdIsZero(dot)){ | |
253 | ccdSimplexSet(portal, 1, ccdSimplexPoint(portal, 3)); | |
254 | cont = 1; | |
255 | } | |
256 | } | |
257 | ||
258 | if (cont){ | |
259 | ccdVec3Sub2(&va, &ccdSimplexPoint(portal, 1)->v, | |
260 | &ccdSimplexPoint(portal, 0)->v); | |
261 | ccdVec3Sub2(&vb, &ccdSimplexPoint(portal, 2)->v, | |
262 | &ccdSimplexPoint(portal, 0)->v); | |
263 | ccdVec3Cross(&dir, &va, &vb); | |
264 | ccdVec3Normalize(&dir); | |
265 | }else{ | |
266 | ccdSimplexSetSize(portal, 4); | |
267 | } | |
268 | } | |
269 | ||
270 | return 0; | |
271 | } | |
272 | ||
273 | static int refinePortal(const void *obj1, const void *obj2, | |
274 | const ccd_t *ccd, ccd_simplex_t *portal) | |
275 | { | |
276 | ccd_vec3_t dir; | |
277 | ccd_support_t v4; | |
278 | ||
279 | while (1){ | |
280 | // compute direction outside the portal (from v0 throught v1,v2,v3 | |
281 | // face) | |
282 | portalDir(portal, &dir); | |
283 | ||
284 | // test if origin is inside the portal | |
285 | if (portalEncapsulesOrigin(portal, &dir)) | |
286 | return 0; | |
287 | ||
288 | // get next support point | |
289 | __ccdSupport(obj1, obj2, &dir, ccd, &v4); | |
290 | ||
291 | // test if v4 can expand portal to contain origin and if portal | |
292 | // expanding doesn't reach given tolerance | |
293 | if (!portalCanEncapsuleOrigin(portal, &v4, &dir) | |
294 | || portalReachTolerance(portal, &v4, &dir, ccd)){ | |
295 | return -1; | |
296 | } | |
297 | ||
298 | // v1-v2-v3 triangle must be rearranged to face outside Minkowski | |
299 | // difference (direction from v0). | |
300 | expandPortal(portal, &v4); | |
301 | } | |
302 | ||
303 | return -1; | |
304 | } | |
305 | ||
306 | ||
307 | static void findPenetr(const void *obj1, const void *obj2, const ccd_t *ccd, | |
308 | ccd_simplex_t *portal, | |
309 | ccd_real_t *depth, ccd_vec3_t *pdir, ccd_vec3_t *pos) | |
310 | { | |
311 | ccd_vec3_t dir; | |
312 | ccd_support_t v4; | |
313 | unsigned long iterations; | |
314 | ||
315 | iterations = 0UL; | |
316 | while (1){ | |
317 | // compute portal direction and obtain next support point | |
318 | portalDir(portal, &dir); | |
319 | __ccdSupport(obj1, obj2, &dir, ccd, &v4); | |
320 | ||
321 | // reached tolerance -> find penetration info | |
322 | if (portalReachTolerance(portal, &v4, &dir, ccd) | |
323 | || iterations > ccd->max_iterations){ | |
324 | *depth = ccdVec3PointTriDist2(ccd_vec3_origin, | |
325 | &ccdSimplexPoint(portal, 1)->v, | |
326 | &ccdSimplexPoint(portal, 2)->v, | |
327 | &ccdSimplexPoint(portal, 3)->v, | |
328 | pdir); | |
329 | *depth = CCD_SQRT(*depth); | |
330 | ccdVec3Normalize(pdir); | |
331 | ||
332 | // barycentric coordinates: | |
333 | findPos(obj1, obj2, ccd, portal, pos); | |
334 | ||
335 | return; | |
336 | } | |
337 | ||
338 | expandPortal(portal, &v4); | |
339 | ||
340 | iterations++; | |
341 | } | |
342 | } | |
343 | ||
344 | static void findPenetrTouch(const void *obj1, const void *obj2, const ccd_t *ccd, | |
345 | ccd_simplex_t *portal, | |
346 | ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos) | |
347 | { | |
348 | // Touching contact on portal's v1 - so depth is zero and direction | |
349 | // is unimportant and pos can be guessed | |
350 | *depth = CCD_REAL(0.); | |
351 | ccdVec3Copy(dir, ccd_vec3_origin); | |
352 | ||
353 | ccdVec3Copy(pos, &ccdSimplexPoint(portal, 1)->v1); | |
354 | ccdVec3Add(pos, &ccdSimplexPoint(portal, 1)->v2); | |
355 | ccdVec3Scale(pos, 0.5); | |
356 | } | |
357 | ||
358 | static void findPenetrSegment(const void *obj1, const void *obj2, const ccd_t *ccd, | |
359 | ccd_simplex_t *portal, | |
360 | ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos) | |
361 | { | |
362 | /* | |
363 | ccd_vec3_t vec; | |
364 | ccd_real_t k; | |
365 | */ | |
366 | ||
367 | // Origin lies on v0-v1 segment. | |
368 | // Depth is distance to v1, direction also and position must be | |
369 | // computed | |
370 | ||
371 | ccdVec3Copy(pos, &ccdSimplexPoint(portal, 1)->v1); | |
372 | ccdVec3Add(pos, &ccdSimplexPoint(portal, 1)->v2); | |
373 | ccdVec3Scale(pos, CCD_REAL(0.5)); | |
374 | ||
375 | /* | |
376 | ccdVec3Sub2(&vec, &ccdSimplexPoint(portal, 1)->v, | |
377 | &ccdSimplexPoint(portal, 0)->v); | |
378 | k = CCD_SQRT(ccdVec3Len2(&ccdSimplexPoint(portal, 0)->v)); | |
379 | k /= CCD_SQRT(ccdVec3Len2(&vec)); | |
380 | ccdVec3Scale(&vec, -k); | |
381 | ccdVec3Add(pos, &vec); | |
382 | */ | |
383 | ||
384 | ccdVec3Copy(dir, &ccdSimplexPoint(portal, 1)->v); | |
385 | *depth = CCD_SQRT(ccdVec3Len2(dir)); | |
386 | ccdVec3Normalize(dir); | |
387 | } | |
388 | ||
389 | ||
390 | static void findPos(const void *obj1, const void *obj2, const ccd_t *ccd, | |
391 | const ccd_simplex_t *portal, ccd_vec3_t *pos) | |
392 | { | |
393 | ccd_vec3_t dir; | |
394 | size_t i; | |
395 | ccd_real_t b[4], sum, inv; | |
396 | ccd_vec3_t vec, p1, p2; | |
397 | ||
398 | portalDir(portal, &dir); | |
399 | ||
400 | // use barycentric coordinates of tetrahedron to find origin | |
401 | ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 1)->v, | |
402 | &ccdSimplexPoint(portal, 2)->v); | |
403 | b[0] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 3)->v); | |
404 | ||
405 | ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 3)->v, | |
406 | &ccdSimplexPoint(portal, 2)->v); | |
407 | b[1] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 0)->v); | |
408 | ||
409 | ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 0)->v, | |
410 | &ccdSimplexPoint(portal, 1)->v); | |
411 | b[2] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 3)->v); | |
412 | ||
413 | ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 2)->v, | |
414 | &ccdSimplexPoint(portal, 1)->v); | |
415 | b[3] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 0)->v); | |
416 | ||
417 | sum = b[0] + b[1] + b[2] + b[3]; | |
418 | ||
419 | if (ccdIsZero(sum) || sum < CCD_ZERO){ | |
420 | b[0] = CCD_REAL(0.); | |
421 | ||
422 | ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 2)->v, | |
423 | &ccdSimplexPoint(portal, 3)->v); | |
424 | b[1] = ccdVec3Dot(&vec, &dir); | |
425 | ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 3)->v, | |
426 | &ccdSimplexPoint(portal, 1)->v); | |
427 | b[2] = ccdVec3Dot(&vec, &dir); | |
428 | ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 1)->v, | |
429 | &ccdSimplexPoint(portal, 2)->v); | |
430 | b[3] = ccdVec3Dot(&vec, &dir); | |
431 | ||
432 | sum = b[1] + b[2] + b[3]; | |
433 | } | |
434 | ||
435 | inv = CCD_REAL(1.) / sum; | |
436 | ||
437 | ccdVec3Copy(&p1, ccd_vec3_origin); | |
438 | ccdVec3Copy(&p2, ccd_vec3_origin); | |
439 | for (i = 0; i < 4; i++){ | |
440 | ccdVec3Copy(&vec, &ccdSimplexPoint(portal, i)->v1); | |
441 | ccdVec3Scale(&vec, b[i]); | |
442 | ccdVec3Add(&p1, &vec); | |
443 | ||
444 | ccdVec3Copy(&vec, &ccdSimplexPoint(portal, i)->v2); | |
445 | ccdVec3Scale(&vec, b[i]); | |
446 | ccdVec3Add(&p2, &vec); | |
447 | } | |
448 | ccdVec3Scale(&p1, inv); | |
449 | ccdVec3Scale(&p2, inv); | |
450 | ||
451 | ccdVec3Copy(pos, &p1); | |
452 | ccdVec3Add(pos, &p2); | |
453 | ccdVec3Scale(pos, 0.5); | |
454 | } | |
455 | ||
456 | _ccd_inline void expandPortal(ccd_simplex_t *portal, | |
457 | const ccd_support_t *v4) | |
458 | { | |
459 | ccd_real_t dot; | |
460 | ccd_vec3_t v4v0; | |
461 | ||
462 | ccdVec3Cross(&v4v0, &v4->v, &ccdSimplexPoint(portal, 0)->v); | |
463 | dot = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, &v4v0); | |
464 | if (dot > CCD_ZERO){ | |
465 | dot = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, &v4v0); | |
466 | if (dot > CCD_ZERO){ | |
467 | ccdSimplexSet(portal, 1, v4); | |
468 | }else{ | |
469 | ccdSimplexSet(portal, 3, v4); | |
470 | } | |
471 | }else{ | |
472 | dot = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, &v4v0); | |
473 | if (dot > CCD_ZERO){ | |
474 | ccdSimplexSet(portal, 2, v4); | |
475 | }else{ | |
476 | ccdSimplexSet(portal, 1, v4); | |
477 | } | |
478 | } | |
479 | } | |
480 | ||
481 | _ccd_inline void portalDir(const ccd_simplex_t *portal, ccd_vec3_t *dir) | |
482 | { | |
483 | ccd_vec3_t v2v1, v3v1; | |
484 | ||
485 | ccdVec3Sub2(&v2v1, &ccdSimplexPoint(portal, 2)->v, | |
486 | &ccdSimplexPoint(portal, 1)->v); | |
487 | ccdVec3Sub2(&v3v1, &ccdSimplexPoint(portal, 3)->v, | |
488 | &ccdSimplexPoint(portal, 1)->v); | |
489 | ccdVec3Cross(dir, &v2v1, &v3v1); | |
490 | ccdVec3Normalize(dir); | |
491 | } | |
492 | ||
493 | _ccd_inline int portalEncapsulesOrigin(const ccd_simplex_t *portal, | |
494 | const ccd_vec3_t *dir) | |
495 | { | |
496 | ccd_real_t dot; | |
497 | dot = ccdVec3Dot(dir, &ccdSimplexPoint(portal, 1)->v); | |
498 | return ccdIsZero(dot) || dot > CCD_ZERO; | |
499 | } | |
500 | ||
501 | _ccd_inline int portalReachTolerance(const ccd_simplex_t *portal, | |
502 | const ccd_support_t *v4, | |
503 | const ccd_vec3_t *dir, | |
504 | const ccd_t *ccd) | |
505 | { | |
506 | ccd_real_t dv1, dv2, dv3, dv4; | |
507 | ccd_real_t dot1, dot2, dot3; | |
508 | ||
509 | // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4} | |
510 | ||
511 | dv1 = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, dir); | |
512 | dv2 = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, dir); | |
513 | dv3 = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, dir); | |
514 | dv4 = ccdVec3Dot(&v4->v, dir); | |
515 | ||
516 | dot1 = dv4 - dv1; | |
517 | dot2 = dv4 - dv2; | |
518 | dot3 = dv4 - dv3; | |
519 | ||
520 | dot1 = CCD_FMIN(dot1, dot2); | |
521 | dot1 = CCD_FMIN(dot1, dot3); | |
522 | ||
523 | return ccdEq(dot1, ccd->mpr_tolerance) || dot1 < ccd->mpr_tolerance; | |
524 | } | |
525 | ||
526 | _ccd_inline int portalCanEncapsuleOrigin(const ccd_simplex_t *portal, | |
527 | const ccd_support_t *v4, | |
528 | const ccd_vec3_t *dir) | |
529 | { | |
530 | ccd_real_t dot; | |
531 | dot = ccdVec3Dot(&v4->v, dir); | |
532 | return ccdIsZero(dot) || dot > CCD_ZERO; | |
533 | } |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #include <stdio.h> | |
18 | #include <float.h> | |
19 | #include <ccd/polytope.h> | |
20 | #include <ccd/alloc.h> | |
21 | ||
22 | _ccd_inline void _ccdPtNearestUpdate(ccd_pt_t *pt, ccd_pt_el_t *el) | |
23 | { | |
24 | if (ccdEq(pt->nearest_dist, el->dist)){ | |
25 | if (el->type < pt->nearest_type){ | |
26 | pt->nearest = el; | |
27 | pt->nearest_dist = el->dist; | |
28 | pt->nearest_type = el->type; | |
29 | } | |
30 | }else if (el->dist < pt->nearest_dist){ | |
31 | pt->nearest = el; | |
32 | pt->nearest_dist = el->dist; | |
33 | pt->nearest_type = el->type; | |
34 | } | |
35 | } | |
36 | ||
37 | static void _ccdPtNearestRenew(ccd_pt_t *pt) | |
38 | { | |
39 | ccd_pt_vertex_t *v; | |
40 | ccd_pt_edge_t *e; | |
41 | ccd_pt_face_t *f; | |
42 | ||
43 | pt->nearest_dist = CCD_REAL_MAX; | |
44 | pt->nearest_type = 3; | |
45 | pt->nearest = NULL; | |
46 | ||
47 | ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ | |
48 | _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)v); | |
49 | } | |
50 | ||
51 | ccdListForEachEntry(&pt->edges, e, ccd_pt_edge_t, list){ | |
52 | _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)e); | |
53 | } | |
54 | ||
55 | ccdListForEachEntry(&pt->faces, f, ccd_pt_face_t, list){ | |
56 | _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)f); | |
57 | } | |
58 | } | |
59 | ||
60 | ||
61 | ||
62 | void ccdPtInit(ccd_pt_t *pt) | |
63 | { | |
64 | ccdListInit(&pt->vertices); | |
65 | ccdListInit(&pt->edges); | |
66 | ccdListInit(&pt->faces); | |
67 | ||
68 | pt->nearest = NULL; | |
69 | pt->nearest_dist = CCD_REAL_MAX; | |
70 | pt->nearest_type = 3; | |
71 | } | |
72 | ||
73 | void ccdPtDestroy(ccd_pt_t *pt) | |
74 | { | |
75 | ccd_pt_face_t *f, *f2; | |
76 | ccd_pt_edge_t *e, *e2; | |
77 | ccd_pt_vertex_t *v, *v2; | |
78 | ||
79 | // first delete all faces | |
80 | ccdListForEachEntrySafe(&pt->faces, f, ccd_pt_face_t, f2, ccd_pt_face_t, list){ | |
81 | ccdPtDelFace(pt, f); | |
82 | } | |
83 | ||
84 | // delete all edges | |
85 | ccdListForEachEntrySafe(&pt->edges, e, ccd_pt_edge_t, e2, ccd_pt_edge_t, list){ | |
86 | ccdPtDelEdge(pt, e); | |
87 | } | |
88 | ||
89 | // delete all vertices | |
90 | ccdListForEachEntrySafe(&pt->vertices, v, ccd_pt_vertex_t, v2, ccd_pt_vertex_t, list){ | |
91 | ccdPtDelVertex(pt, v); | |
92 | } | |
93 | } | |
94 | ||
95 | ||
96 | ccd_pt_vertex_t *ccdPtAddVertex(ccd_pt_t *pt, const ccd_support_t *v) | |
97 | { | |
98 | ccd_pt_vertex_t *vert; | |
99 | ||
100 | vert = CCD_ALLOC(ccd_pt_vertex_t); | |
101 | if (vert == NULL) | |
102 | return NULL; | |
103 | ||
104 | vert->type = CCD_PT_VERTEX; | |
105 | ccdSupportCopy(&vert->v, v); | |
106 | ||
107 | vert->dist = ccdVec3Len2(&vert->v.v); | |
108 | ccdVec3Copy(&vert->witness, &vert->v.v); | |
109 | ||
110 | ccdListInit(&vert->edges); | |
111 | ||
112 | // add vertex to list | |
113 | ccdListAppend(&pt->vertices, &vert->list); | |
114 | ||
115 | // update position in .nearest array | |
116 | _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)vert); | |
117 | ||
118 | return vert; | |
119 | } | |
120 | ||
121 | ccd_pt_edge_t *ccdPtAddEdge(ccd_pt_t *pt, ccd_pt_vertex_t *v1, | |
122 | ccd_pt_vertex_t *v2) | |
123 | { | |
124 | const ccd_vec3_t *a, *b; | |
125 | ccd_pt_edge_t *edge; | |
126 | ||
127 | if (v1 == NULL || v2 == NULL) | |
128 | return NULL; | |
129 | ||
130 | edge = CCD_ALLOC(ccd_pt_edge_t); | |
131 | if (edge == NULL) | |
132 | return NULL; | |
133 | ||
134 | edge->type = CCD_PT_EDGE; | |
135 | edge->vertex[0] = v1; | |
136 | edge->vertex[1] = v2; | |
137 | edge->faces[0] = edge->faces[1] = NULL; | |
138 | ||
139 | a = &edge->vertex[0]->v.v; | |
140 | b = &edge->vertex[1]->v.v; | |
141 | edge->dist = ccdVec3PointSegmentDist2(ccd_vec3_origin, a, b, &edge->witness); | |
142 | ||
143 | ccdListAppend(&edge->vertex[0]->edges, &edge->vertex_list[0]); | |
144 | ccdListAppend(&edge->vertex[1]->edges, &edge->vertex_list[1]); | |
145 | ||
146 | ccdListAppend(&pt->edges, &edge->list); | |
147 | ||
148 | // update position in .nearest array | |
149 | _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)edge); | |
150 | ||
151 | return edge; | |
152 | } | |
153 | ||
154 | ccd_pt_face_t *ccdPtAddFace(ccd_pt_t *pt, ccd_pt_edge_t *e1, | |
155 | ccd_pt_edge_t *e2, | |
156 | ccd_pt_edge_t *e3) | |
157 | { | |
158 | const ccd_vec3_t *a, *b, *c; | |
159 | ccd_pt_face_t *face; | |
160 | ccd_pt_edge_t *e; | |
161 | size_t i; | |
162 | ||
163 | if (e1 == NULL || e2 == NULL || e3 == NULL) | |
164 | return NULL; | |
165 | ||
166 | face = CCD_ALLOC(ccd_pt_face_t); | |
167 | if (face == NULL) | |
168 | return NULL; | |
169 | ||
170 | face->type = CCD_PT_FACE; | |
171 | face->edge[0] = e1; | |
172 | face->edge[1] = e2; | |
173 | face->edge[2] = e3; | |
174 | ||
175 | // obtain triplet of vertices | |
176 | a = &face->edge[0]->vertex[0]->v.v; | |
177 | b = &face->edge[0]->vertex[1]->v.v; | |
178 | e = face->edge[1]; | |
179 | if (e->vertex[0] != face->edge[0]->vertex[0] | |
180 | && e->vertex[0] != face->edge[0]->vertex[1]){ | |
181 | c = &e->vertex[0]->v.v; | |
182 | }else{ | |
183 | c = &e->vertex[1]->v.v; | |
184 | } | |
185 | face->dist = ccdVec3PointTriDist2(ccd_vec3_origin, a, b, c, &face->witness); | |
186 | ||
187 | ||
188 | for (i = 0; i < 3; i++){ | |
189 | if (face->edge[i]->faces[0] == NULL){ | |
190 | face->edge[i]->faces[0] = face; | |
191 | }else{ | |
192 | face->edge[i]->faces[1] = face; | |
193 | } | |
194 | } | |
195 | ||
196 | ccdListAppend(&pt->faces, &face->list); | |
197 | ||
198 | // update position in .nearest array | |
199 | _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)face); | |
200 | ||
201 | return face; | |
202 | } | |
203 | ||
204 | ||
205 | void ccdPtRecomputeDistances(ccd_pt_t *pt) | |
206 | { | |
207 | ccd_pt_vertex_t *v; | |
208 | ccd_pt_edge_t *e; | |
209 | ccd_pt_face_t *f; | |
210 | const ccd_vec3_t *a, *b, *c; | |
211 | ccd_real_t dist; | |
212 | ||
213 | ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ | |
214 | dist = ccdVec3Len2(&v->v.v); | |
215 | v->dist = dist; | |
216 | ccdVec3Copy(&v->witness, &v->v.v); | |
217 | } | |
218 | ||
219 | ccdListForEachEntry(&pt->edges, e, ccd_pt_edge_t, list){ | |
220 | a = &e->vertex[0]->v.v; | |
221 | b = &e->vertex[1]->v.v; | |
222 | dist = ccdVec3PointSegmentDist2(ccd_vec3_origin, a, b, &e->witness); | |
223 | e->dist = dist; | |
224 | } | |
225 | ||
226 | ccdListForEachEntry(&pt->faces, f, ccd_pt_face_t, list){ | |
227 | // obtain triplet of vertices | |
228 | a = &f->edge[0]->vertex[0]->v.v; | |
229 | b = &f->edge[0]->vertex[1]->v.v; | |
230 | e = f->edge[1]; | |
231 | if (e->vertex[0] != f->edge[0]->vertex[0] | |
232 | && e->vertex[0] != f->edge[0]->vertex[1]){ | |
233 | c = &e->vertex[0]->v.v; | |
234 | }else{ | |
235 | c = &e->vertex[1]->v.v; | |
236 | } | |
237 | ||
238 | dist = ccdVec3PointTriDist2(ccd_vec3_origin, a, b, c, &f->witness); | |
239 | f->dist = dist; | |
240 | } | |
241 | } | |
242 | ||
243 | ccd_pt_el_t *ccdPtNearest(ccd_pt_t *pt) | |
244 | { | |
245 | if (!pt->nearest){ | |
246 | _ccdPtNearestRenew(pt); | |
247 | } | |
248 | return pt->nearest; | |
249 | } | |
250 | ||
251 | ||
252 | void ccdPtDumpSVT(ccd_pt_t *pt, const char *fn) | |
253 | { | |
254 | FILE *fout; | |
255 | ||
256 | fout = fopen(fn, "a"); | |
257 | if (fout == NULL) | |
258 | return; | |
259 | ||
260 | ccdPtDumpSVT2(pt, fout); | |
261 | ||
262 | fclose(fout); | |
263 | } | |
264 | ||
265 | void ccdPtDumpSVT2(ccd_pt_t *pt, FILE *fout) | |
266 | { | |
267 | ccd_pt_vertex_t *v, *a, *b, *c; | |
268 | ccd_pt_edge_t *e; | |
269 | ccd_pt_face_t *f; | |
270 | size_t i; | |
271 | ||
272 | fprintf(fout, "-----\n"); | |
273 | ||
274 | fprintf(fout, "Points:\n"); | |
275 | i = 0; | |
276 | ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ | |
277 | v->id = i++; | |
278 | fprintf(fout, "%lf %lf %lf\n", | |
279 | ccdVec3X(&v->v.v), ccdVec3Y(&v->v.v), ccdVec3Z(&v->v.v)); | |
280 | } | |
281 | ||
282 | fprintf(fout, "Edges:\n"); | |
283 | ccdListForEachEntry(&pt->edges, e, ccd_pt_edge_t, list){ | |
284 | fprintf(fout, "%d %d\n", e->vertex[0]->id, e->vertex[1]->id); | |
285 | } | |
286 | ||
287 | fprintf(fout, "Faces:\n"); | |
288 | ccdListForEachEntry(&pt->faces, f, ccd_pt_face_t, list){ | |
289 | a = f->edge[0]->vertex[0]; | |
290 | b = f->edge[0]->vertex[1]; | |
291 | c = f->edge[1]->vertex[0]; | |
292 | if (c == a || c == b){ | |
293 | c = f->edge[1]->vertex[1]; | |
294 | } | |
295 | fprintf(fout, "%d %d %d\n", a->id, b->id, c->id); | |
296 | } | |
297 | } |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #include <ccd/support.h> | |
18 | ||
19 | void __ccdSupport(const void *obj1, const void *obj2, | |
20 | const ccd_vec3_t *_dir, const ccd_t *ccd, | |
21 | ccd_support_t *supp) | |
22 | { | |
23 | ccd_vec3_t dir; | |
24 | ||
25 | ccdVec3Copy(&dir, _dir); | |
26 | ||
27 | ccd->support1(obj1, &dir, &supp->v1); | |
28 | ||
29 | ccdVec3Scale(&dir, -CCD_ONE); | |
30 | ccd->support2(obj2, &dir, &supp->v2); | |
31 | ||
32 | ccdVec3Sub2(&supp->v, &supp->v1, &supp->v2); | |
33 | } |
0 | # force some options | |
1 | DEBUG = yes | |
2 | ||
3 | -include ../Makefile.include | |
4 | CFLAGS += -I./ -I../ -Icu/ | |
5 | LDFLAGS += -L./ -Lcu/ -lcu -lrt -lm -L../ -lccd | |
6 | ||
7 | CHECK_REG=cu/check-regressions | |
8 | CHECK_TS ?= | |
9 | ||
10 | OBJS = common.o support.o vec3.o polytope.o boxbox.o spheresphere.o \ | |
11 | cylcyl.o boxcyl.o mpr_boxbox.o mpr_cylcyl.o mpr_boxcyl.o | |
12 | BENCH_OBJS = bench-boxbox.o | |
13 | ||
14 | ||
15 | all: test bench bench2 | |
16 | ||
17 | test: cu $(OBJS) main.c | |
18 | $(CC) $(CFLAGS) -o $@ main.c $(OBJS) $(LDFLAGS) | |
19 | ||
20 | bench: cu bench.c support.o | |
21 | $(CC) $(CFLAGS) -o $@ bench.c support.o $(LDFLAGS) | |
22 | bench2: cu bench2.c support.o | |
23 | $(CC) $(CFLAGS) -o $@ bench2.c support.o $(LDFLAGS) | |
24 | ||
25 | %.o: %.c %.h | |
26 | $(CC) $(CFLAGS) -c -o $@ $< | |
27 | %.o: %.c | |
28 | $(CC) $(CFLAGS) -c -o $@ $< | |
29 | ||
30 | check: all | |
31 | @echo "" | |
32 | @echo "----------------------------------------"; | |
33 | ./test $(CHECK_TS) | |
34 | @echo "----------------------------------------"; | |
35 | @echo "Checking regressions:"; | |
36 | $(PYTHON) $(CHECK_REG) regressions | |
37 | @echo "" | |
38 | ||
39 | check-valgrind: all | |
40 | valgrind -q --leak-check=full --show-reachable=yes --trace-children=yes \ | |
41 | --error-limit=no \ | |
42 | ./test $(CHECK_TS) | |
43 | ||
44 | check-valgrind-gen-suppressions: all | |
45 | valgrind -q --leak-check=full --show-reachable=yes --trace-children=yes \ | |
46 | --gen-suppressions=all --log-file=out --error-limit=no \ | |
47 | ./test $(CHECK_TS) | |
48 | ||
49 | cu: | |
50 | $(MAKE) ENABLE_TIMER=yes -C cu/ | |
51 | ||
52 | clean: | |
53 | rm -f *.o | |
54 | rm -f objs/*.o | |
55 | rm -f test bench bench2 | |
56 | rm -f tmp.* | |
57 | rm -f regressions/tmp.* | |
58 | ||
59 | .PHONY: all clean check check-valgrind cu | |
60 |
0 | SUBDIRS = cu | |
1 | ||
2 | AM_CPPFLAGS = -I $(srcdir)/.. -I $(builddir)/.. -I $(srcdir)/cu | |
3 | ||
4 | LDADD = $(builddir)/cu/libcu.la $(builddir)/../libccd.la | |
5 | ||
6 | ||
7 | check_PROGRAMS = test bench bench2 | |
8 | ||
9 | test_SOURCES = main.c \ | |
10 | common.c common.h \ | |
11 | support.c support.h \ | |
12 | vec3.c vec3.h \ | |
13 | polytope.c polytope.h \ | |
14 | boxbox.c boxbox.h \ | |
15 | spheresphere.c spheresphere.h \ | |
16 | cylcyl.c cylcyl.h \ | |
17 | boxcyl.c boxcyl.h \ | |
18 | mpr_boxbox.c mpr_boxbox.h \ | |
19 | mpr_cylcyl.c mpr_cylcyl.h \ | |
20 | mpr_boxcyl.c mpr_boxcyl.h | |
21 | ||
22 | bench_SOURCES = bench.c \ | |
23 | support.c support.h | |
24 | ||
25 | bench2_SOURCES = bench2.c \ | |
26 | support.c support.h | |
27 |
0 | #define CU_ENABLE_TIMER | |
1 | #include <cu/cu.h> | |
2 | #include <stdio.h> | |
3 | #include <stdlib.h> | |
4 | #include <ccd/ccd.h> | |
5 | #include "support.h" | |
6 | ||
7 | TEST_SUITES { | |
8 | TEST_SUITES_CLOSURE | |
9 | }; | |
10 | ||
11 | static int bench_num = 1; | |
12 | static size_t cycles = 10000; | |
13 | ||
14 | static void runBench(const void *o1, const void *o2, const ccd_t *ccd) | |
15 | { | |
16 | ccd_real_t depth; | |
17 | ccd_vec3_t dir, pos; | |
18 | size_t i; | |
19 | const struct timespec *timer; | |
20 | ||
21 | cuTimerStart(); | |
22 | for (i = 0; i < cycles; i++){ | |
23 | ccdGJKPenetration(o1, o2, ccd, &depth, &dir, &pos); | |
24 | } | |
25 | timer = cuTimerStop(); | |
26 | fprintf(stdout, "%02d: %ld %ld\n", bench_num, | |
27 | (long)timer->tv_sec, (long)timer->tv_nsec); | |
28 | fflush(stdout); | |
29 | ||
30 | bench_num++; | |
31 | } | |
32 | ||
33 | static void boxbox(void) | |
34 | { | |
35 | fprintf(stdout, "%s:\n", __func__); | |
36 | ||
37 | ccd_t ccd; | |
38 | CCD_BOX(box1); | |
39 | CCD_BOX(box2); | |
40 | ccd_vec3_t axis; | |
41 | ccd_quat_t rot; | |
42 | ||
43 | box1.x = box1.y = box1.z = 1.; | |
44 | box2.x = 0.5; | |
45 | box2.y = 1.; | |
46 | box2.z = 1.5; | |
47 | ||
48 | bench_num = 1; | |
49 | ||
50 | CCD_INIT(&ccd); | |
51 | ccd.support1 = ccdSupport; | |
52 | ccd.support2 = ccdSupport; | |
53 | ||
54 | runBench(&box1, &box2, &ccd); | |
55 | runBench(&box2, &box1, &ccd); | |
56 | ||
57 | ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); | |
58 | runBench(&box1, &box2, &ccd); | |
59 | runBench(&box2, &box1, &ccd); | |
60 | ||
61 | box1.x = box1.y = box1.z = 1.; | |
62 | box2.x = box2.y = box2.z = 1.; | |
63 | ccdVec3Set(&axis, 0., 0., 1.); | |
64 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
65 | ccdVec3Set(&box1.pos, 0., 0., 0.); | |
66 | runBench(&box1, &box2, &ccd); | |
67 | runBench(&box2, &box1, &ccd); | |
68 | ||
69 | box1.x = box1.y = box1.z = 1.; | |
70 | box2.x = box2.y = box2.z = 1.; | |
71 | ccdVec3Set(&axis, 0., 0., 1.); | |
72 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
73 | ccdVec3Set(&box1.pos, -0.5, 0., 0.); | |
74 | runBench(&box1, &box2, &ccd); | |
75 | runBench(&box2, &box1, &ccd); | |
76 | ||
77 | box1.x = box1.y = box1.z = 1.; | |
78 | box2.x = box2.y = box2.z = 1.; | |
79 | ccdVec3Set(&axis, 0., 0., 1.); | |
80 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
81 | ccdVec3Set(&box1.pos, -0.5, 0.5, 0.); | |
82 | runBench(&box1, &box2, &ccd); | |
83 | runBench(&box2, &box1, &ccd); | |
84 | ||
85 | box1.x = box1.y = box1.z = 1.; | |
86 | ccdVec3Set(&axis, 0., 1., 1.); | |
87 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
88 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
89 | runBench(&box1, &box2, &ccd); | |
90 | runBench(&box2, &box1, &ccd); | |
91 | ||
92 | box1.x = box1.y = box1.z = 1.; | |
93 | ccdVec3Set(&axis, 0., 1., 1.); | |
94 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
95 | ccdVec3Set(&axis, 1., 1., 1.); | |
96 | ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); | |
97 | ccdQuatMul(&box1.quat, &rot); | |
98 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
99 | runBench(&box1, &box2, &ccd); | |
100 | runBench(&box2, &box1, &ccd); | |
101 | ||
102 | ||
103 | box1.x = box1.y = box1.z = 1.; | |
104 | box2.x = 0.2; box2.y = 0.5; box2.z = 1.; | |
105 | box2.x = box2.y = box2.z = 1.; | |
106 | ||
107 | ccdVec3Set(&axis, 0., 0., 1.); | |
108 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
109 | ccdVec3Set(&axis, 1., 0., 0.); | |
110 | ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); | |
111 | ccdQuatMul(&box1.quat, &rot); | |
112 | ccdVec3Set(&box1.pos, -1.3, 0., 0.); | |
113 | ||
114 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
115 | runBench(&box1, &box2, &ccd); | |
116 | runBench(&box2, &box1, &ccd); | |
117 | ||
118 | ||
119 | fprintf(stdout, "\n----\n\n"); | |
120 | } | |
121 | ||
122 | void cylcyl(void) | |
123 | { | |
124 | fprintf(stdout, "%s:\n", __func__); | |
125 | ||
126 | ccd_t ccd; | |
127 | CCD_CYL(cyl1); | |
128 | CCD_CYL(cyl2); | |
129 | ccd_vec3_t axis; | |
130 | ||
131 | cyl1.radius = 0.35; | |
132 | cyl1.height = 0.5; | |
133 | cyl2.radius = 0.5; | |
134 | cyl2.height = 1.; | |
135 | ||
136 | CCD_INIT(&ccd); | |
137 | ccd.support1 = ccdSupport; | |
138 | ccd.support2 = ccdSupport; | |
139 | ||
140 | runBench(&cyl1, &cyl2, &ccd); | |
141 | runBench(&cyl2, &cyl1, &ccd); | |
142 | ||
143 | ccdVec3Set(&cyl1.pos, 0.3, 0.1, 0.1); | |
144 | runBench(&cyl1, &cyl2, &ccd); | |
145 | runBench(&cyl2, &cyl1, &ccd); | |
146 | ||
147 | ccdVec3Set(&axis, 0., 1., 1.); | |
148 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
149 | ccdVec3Set(&cyl2.pos, 0., 0., 0.); | |
150 | runBench(&cyl1, &cyl2, &ccd); | |
151 | runBench(&cyl2, &cyl1, &ccd); | |
152 | ||
153 | ccdVec3Set(&axis, 0., 1., 1.); | |
154 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
155 | ccdVec3Set(&cyl2.pos, -0.2, 0.7, 0.2); | |
156 | runBench(&cyl1, &cyl2, &ccd); | |
157 | runBench(&cyl2, &cyl1, &ccd); | |
158 | ||
159 | ccdVec3Set(&axis, 0.567, 1.2, 1.); | |
160 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
161 | ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); | |
162 | runBench(&cyl1, &cyl2, &ccd); | |
163 | runBench(&cyl2, &cyl1, &ccd); | |
164 | ||
165 | ccdVec3Set(&axis, -4.567, 1.2, 0.); | |
166 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 3., &axis); | |
167 | ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); | |
168 | runBench(&cyl1, &cyl2, &ccd); | |
169 | runBench(&cyl2, &cyl1, &ccd); | |
170 | ||
171 | fprintf(stdout, "\n----\n\n"); | |
172 | } | |
173 | ||
174 | void boxcyl(void) | |
175 | { | |
176 | fprintf(stdout, "%s:\n", __func__); | |
177 | ||
178 | ccd_t ccd; | |
179 | CCD_BOX(box); | |
180 | CCD_CYL(cyl); | |
181 | ccd_vec3_t axis; | |
182 | ||
183 | box.x = 0.5; | |
184 | box.y = 1.; | |
185 | box.z = 1.5; | |
186 | cyl.radius = 0.4; | |
187 | cyl.height = 0.7; | |
188 | ||
189 | CCD_INIT(&ccd); | |
190 | ccd.support1 = ccdSupport; | |
191 | ccd.support2 = ccdSupport; | |
192 | ||
193 | runBench(&box, &cyl, &ccd); | |
194 | runBench(&cyl, &box, &ccd); | |
195 | ||
196 | ccdVec3Set(&cyl.pos, .6, 0., 0.); | |
197 | runBench(&box, &cyl, &ccd); | |
198 | runBench(&cyl, &box, &ccd); | |
199 | ||
200 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.); | |
201 | runBench(&box, &cyl, &ccd); | |
202 | runBench(&cyl, &box, &ccd); | |
203 | ||
204 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
205 | runBench(&box, &cyl, &ccd); | |
206 | runBench(&cyl, &box, &ccd); | |
207 | ||
208 | ccdVec3Set(&axis, 0., 1., 0.); | |
209 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); | |
210 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
211 | runBench(&box, &cyl, &ccd); | |
212 | runBench(&cyl, &box, &ccd); | |
213 | ||
214 | ccdVec3Set(&axis, 0.67, 1.1, 0.12); | |
215 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); | |
216 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
217 | runBench(&box, &cyl, &ccd); | |
218 | runBench(&cyl, &box, &ccd); | |
219 | ||
220 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
221 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
222 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
223 | ccdVec3Set(&axis, 1., 1., 0.); | |
224 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
225 | ccdVec3Set(&box.pos, .6, 0., 0.5); | |
226 | runBench(&box, &cyl, &ccd); | |
227 | runBench(&cyl, &box, &ccd); | |
228 | ||
229 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
230 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
231 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
232 | ccdVec3Set(&axis, 1., 1., 0.); | |
233 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
234 | ccdVec3Set(&box.pos, .9, 0.8, 0.5); | |
235 | runBench(&box, &cyl, &ccd); | |
236 | runBench(&cyl, &box, &ccd); | |
237 | ||
238 | fprintf(stdout, "\n----\n\n"); | |
239 | } | |
240 | ||
241 | int main(int argc, char *argv[]) | |
242 | { | |
243 | if (argc > 1){ | |
244 | cycles = atol(argv[1]); | |
245 | } | |
246 | ||
247 | fprintf(stdout, "Cycles: %u\n", (unsigned int)cycles); | |
248 | fprintf(stdout, "\n"); | |
249 | ||
250 | boxbox(); | |
251 | cylcyl(); | |
252 | boxcyl(); | |
253 | ||
254 | return 0; | |
255 | } |
0 | #define CU_ENABLE_TIMER | |
1 | #include <cu/cu.h> | |
2 | #include <stdio.h> | |
3 | #include <stdlib.h> | |
4 | #include <ccd/ccd.h> | |
5 | #include "support.h" | |
6 | ||
7 | TEST_SUITES { | |
8 | TEST_SUITES_CLOSURE | |
9 | }; | |
10 | ||
11 | static int bench_num = 1; | |
12 | static size_t cycles = 10000; | |
13 | ||
14 | static void runBench(const void *o1, const void *o2, const ccd_t *ccd) | |
15 | { | |
16 | ccd_real_t depth; | |
17 | ccd_vec3_t dir, pos; | |
18 | size_t i; | |
19 | const struct timespec *timer; | |
20 | ||
21 | cuTimerStart(); | |
22 | for (i = 0; i < cycles; i++){ | |
23 | ccdMPRPenetration(o1, o2, ccd, &depth, &dir, &pos); | |
24 | } | |
25 | timer = cuTimerStop(); | |
26 | fprintf(stdout, "%02d: %ld %ld\n", bench_num, | |
27 | (long)timer->tv_sec, (long)timer->tv_nsec); | |
28 | fflush(stdout); | |
29 | ||
30 | bench_num++; | |
31 | } | |
32 | ||
33 | static void boxbox(void) | |
34 | { | |
35 | fprintf(stdout, "%s:\n", __func__); | |
36 | ||
37 | ccd_t ccd; | |
38 | CCD_BOX(box1); | |
39 | CCD_BOX(box2); | |
40 | ccd_vec3_t axis; | |
41 | ccd_quat_t rot; | |
42 | ||
43 | box1.x = box1.y = box1.z = 1.; | |
44 | box2.x = 0.5; | |
45 | box2.y = 1.; | |
46 | box2.z = 1.5; | |
47 | ||
48 | bench_num = 1; | |
49 | ||
50 | CCD_INIT(&ccd); | |
51 | ccd.support1 = ccdSupport; | |
52 | ccd.support2 = ccdSupport; | |
53 | ccd.center1 = ccdObjCenter; | |
54 | ccd.center2 = ccdObjCenter; | |
55 | ||
56 | runBench(&box1, &box2, &ccd); | |
57 | runBench(&box2, &box1, &ccd); | |
58 | ||
59 | ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); | |
60 | runBench(&box1, &box2, &ccd); | |
61 | runBench(&box2, &box1, &ccd); | |
62 | ||
63 | box1.x = box1.y = box1.z = 1.; | |
64 | box2.x = box2.y = box2.z = 1.; | |
65 | ccdVec3Set(&axis, 0., 0., 1.); | |
66 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
67 | ccdVec3Set(&box1.pos, 0., 0., 0.); | |
68 | runBench(&box1, &box2, &ccd); | |
69 | runBench(&box2, &box1, &ccd); | |
70 | ||
71 | box1.x = box1.y = box1.z = 1.; | |
72 | box2.x = box2.y = box2.z = 1.; | |
73 | ccdVec3Set(&axis, 0., 0., 1.); | |
74 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
75 | ccdVec3Set(&box1.pos, -0.5, 0., 0.); | |
76 | runBench(&box1, &box2, &ccd); | |
77 | runBench(&box2, &box1, &ccd); | |
78 | ||
79 | box1.x = box1.y = box1.z = 1.; | |
80 | box2.x = box2.y = box2.z = 1.; | |
81 | ccdVec3Set(&axis, 0., 0., 1.); | |
82 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
83 | ccdVec3Set(&box1.pos, -0.5, 0.5, 0.); | |
84 | runBench(&box1, &box2, &ccd); | |
85 | runBench(&box2, &box1, &ccd); | |
86 | ||
87 | box1.x = box1.y = box1.z = 1.; | |
88 | ccdVec3Set(&axis, 0., 1., 1.); | |
89 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
90 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
91 | runBench(&box1, &box2, &ccd); | |
92 | runBench(&box2, &box1, &ccd); | |
93 | ||
94 | box1.x = box1.y = box1.z = 1.; | |
95 | ccdVec3Set(&axis, 0., 1., 1.); | |
96 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
97 | ccdVec3Set(&axis, 1., 1., 1.); | |
98 | ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); | |
99 | ccdQuatMul(&box1.quat, &rot); | |
100 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
101 | runBench(&box1, &box2, &ccd); | |
102 | runBench(&box2, &box1, &ccd); | |
103 | ||
104 | ||
105 | box1.x = box1.y = box1.z = 1.; | |
106 | box2.x = 0.2; box2.y = 0.5; box2.z = 1.; | |
107 | box2.x = box2.y = box2.z = 1.; | |
108 | ||
109 | ccdVec3Set(&axis, 0., 0., 1.); | |
110 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
111 | ccdVec3Set(&axis, 1., 0., 0.); | |
112 | ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); | |
113 | ccdQuatMul(&box1.quat, &rot); | |
114 | ccdVec3Set(&box1.pos, -1.3, 0., 0.); | |
115 | ||
116 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
117 | runBench(&box1, &box2, &ccd); | |
118 | runBench(&box2, &box1, &ccd); | |
119 | ||
120 | ||
121 | fprintf(stdout, "\n----\n\n"); | |
122 | } | |
123 | ||
124 | void cylcyl(void) | |
125 | { | |
126 | fprintf(stdout, "%s:\n", __func__); | |
127 | ||
128 | ccd_t ccd; | |
129 | CCD_CYL(cyl1); | |
130 | CCD_CYL(cyl2); | |
131 | ccd_vec3_t axis; | |
132 | ||
133 | cyl1.radius = 0.35; | |
134 | cyl1.height = 0.5; | |
135 | cyl2.radius = 0.5; | |
136 | cyl2.height = 1.; | |
137 | ||
138 | CCD_INIT(&ccd); | |
139 | ccd.support1 = ccdSupport; | |
140 | ccd.support2 = ccdSupport; | |
141 | ccd.center1 = ccdObjCenter; | |
142 | ccd.center2 = ccdObjCenter; | |
143 | ||
144 | runBench(&cyl1, &cyl2, &ccd); | |
145 | runBench(&cyl2, &cyl1, &ccd); | |
146 | ||
147 | ccdVec3Set(&cyl1.pos, 0.3, 0.1, 0.1); | |
148 | runBench(&cyl1, &cyl2, &ccd); | |
149 | runBench(&cyl2, &cyl1, &ccd); | |
150 | ||
151 | ccdVec3Set(&axis, 0., 1., 1.); | |
152 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
153 | ccdVec3Set(&cyl2.pos, 0., 0., 0.); | |
154 | runBench(&cyl1, &cyl2, &ccd); | |
155 | runBench(&cyl2, &cyl1, &ccd); | |
156 | ||
157 | ccdVec3Set(&axis, 0., 1., 1.); | |
158 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
159 | ccdVec3Set(&cyl2.pos, -0.2, 0.7, 0.2); | |
160 | runBench(&cyl1, &cyl2, &ccd); | |
161 | runBench(&cyl2, &cyl1, &ccd); | |
162 | ||
163 | ccdVec3Set(&axis, 0.567, 1.2, 1.); | |
164 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
165 | ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); | |
166 | runBench(&cyl1, &cyl2, &ccd); | |
167 | runBench(&cyl2, &cyl1, &ccd); | |
168 | ||
169 | ccdVec3Set(&axis, -4.567, 1.2, 0.); | |
170 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 3., &axis); | |
171 | ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); | |
172 | runBench(&cyl1, &cyl2, &ccd); | |
173 | runBench(&cyl2, &cyl1, &ccd); | |
174 | ||
175 | fprintf(stdout, "\n----\n\n"); | |
176 | } | |
177 | ||
178 | void boxcyl(void) | |
179 | { | |
180 | fprintf(stdout, "%s:\n", __func__); | |
181 | ||
182 | ccd_t ccd; | |
183 | CCD_BOX(box); | |
184 | CCD_CYL(cyl); | |
185 | ccd_vec3_t axis; | |
186 | ||
187 | box.x = 0.5; | |
188 | box.y = 1.; | |
189 | box.z = 1.5; | |
190 | cyl.radius = 0.4; | |
191 | cyl.height = 0.7; | |
192 | ||
193 | CCD_INIT(&ccd); | |
194 | ccd.support1 = ccdSupport; | |
195 | ccd.support2 = ccdSupport; | |
196 | ccd.center1 = ccdObjCenter; | |
197 | ccd.center2 = ccdObjCenter; | |
198 | ||
199 | runBench(&box, &cyl, &ccd); | |
200 | runBench(&cyl, &box, &ccd); | |
201 | ||
202 | ccdVec3Set(&cyl.pos, .6, 0., 0.); | |
203 | runBench(&box, &cyl, &ccd); | |
204 | runBench(&cyl, &box, &ccd); | |
205 | ||
206 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.); | |
207 | runBench(&box, &cyl, &ccd); | |
208 | runBench(&cyl, &box, &ccd); | |
209 | ||
210 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
211 | runBench(&box, &cyl, &ccd); | |
212 | runBench(&cyl, &box, &ccd); | |
213 | ||
214 | ccdVec3Set(&axis, 0., 1., 0.); | |
215 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); | |
216 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
217 | runBench(&box, &cyl, &ccd); | |
218 | runBench(&cyl, &box, &ccd); | |
219 | ||
220 | ccdVec3Set(&axis, 0.67, 1.1, 0.12); | |
221 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); | |
222 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
223 | runBench(&box, &cyl, &ccd); | |
224 | runBench(&cyl, &box, &ccd); | |
225 | ||
226 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
227 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
228 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
229 | ccdVec3Set(&axis, 1., 1., 0.); | |
230 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
231 | ccdVec3Set(&box.pos, .6, 0., 0.5); | |
232 | runBench(&box, &cyl, &ccd); | |
233 | runBench(&cyl, &box, &ccd); | |
234 | ||
235 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
236 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
237 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
238 | ccdVec3Set(&axis, 1., 1., 0.); | |
239 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
240 | ccdVec3Set(&box.pos, .9, 0.8, 0.5); | |
241 | runBench(&box, &cyl, &ccd); | |
242 | runBench(&cyl, &box, &ccd); | |
243 | ||
244 | fprintf(stdout, "\n----\n\n"); | |
245 | } | |
246 | ||
247 | int main(int argc, char *argv[]) | |
248 | { | |
249 | if (argc > 1){ | |
250 | cycles = atol(argv[1]); | |
251 | } | |
252 | ||
253 | fprintf(stdout, "Cycles: %u\n", (unsigned int)cycles); | |
254 | fprintf(stdout, "\n"); | |
255 | ||
256 | boxbox(); | |
257 | cylcyl(); | |
258 | boxcyl(); | |
259 | ||
260 | return 0; | |
261 | } |
0 | #include <stdio.h> | |
1 | #include <cu/cu.h> | |
2 | ||
3 | #include <ccd/ccd.h> | |
4 | #include "support.h" | |
5 | #include <ccd/vec3.h> | |
6 | #include <ccd/dbg.h> | |
7 | #include "common.h" | |
8 | ||
9 | ||
10 | TEST(boxboxSetUp) | |
11 | { | |
12 | } | |
13 | ||
14 | TEST(boxboxTearDown) | |
15 | { | |
16 | } | |
17 | ||
18 | TEST(boxboxAlignedX) | |
19 | { | |
20 | size_t i; | |
21 | ccd_t ccd; | |
22 | CCD_BOX(box1); | |
23 | CCD_BOX(box2); | |
24 | int res; | |
25 | ||
26 | CCD_INIT(&ccd); | |
27 | ccd.support1 = ccdSupport; | |
28 | ccd.support2 = ccdSupport; | |
29 | //ccd.max_iterations = 20; | |
30 | ||
31 | box1.x = 1; | |
32 | box1.y = 2; | |
33 | box1.z = 1; | |
34 | box2.x = 2; | |
35 | box2.y = 1; | |
36 | box2.z = 2; | |
37 | ||
38 | ccdVec3Set(&box1.pos, -5., 0., 0.); | |
39 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
40 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
41 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
42 | for (i = 0; i < 100; i++){ | |
43 | res = ccdGJKIntersect(&box1, &box2, &ccd); | |
44 | if (i < 35 || i > 65){ | |
45 | assertFalse(res); | |
46 | }else if (i != 35 && i != 65){ | |
47 | assertTrue(res); | |
48 | } | |
49 | ||
50 | box1.pos.v[0] += 0.1; | |
51 | } | |
52 | ||
53 | ||
54 | box1.x = 0.1; | |
55 | box1.y = 0.2; | |
56 | box1.z = 0.1; | |
57 | box2.x = 0.2; | |
58 | box2.y = 0.1; | |
59 | box2.z = 0.2; | |
60 | ||
61 | ccdVec3Set(&box1.pos, -0.5, 0., 0.); | |
62 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
63 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
64 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
65 | for (i = 0; i < 100; i++){ | |
66 | res = ccdGJKIntersect(&box1, &box2, &ccd); | |
67 | ||
68 | if (i < 35 || i > 65){ | |
69 | assertFalse(res); | |
70 | }else if (i != 35 && i != 65){ | |
71 | assertTrue(res); | |
72 | } | |
73 | ||
74 | box1.pos.v[0] += 0.01; | |
75 | } | |
76 | ||
77 | ||
78 | box1.x = 1; | |
79 | box1.y = 2; | |
80 | box1.z = 1; | |
81 | box2.x = 2; | |
82 | box2.y = 1; | |
83 | box2.z = 2; | |
84 | ||
85 | ccdVec3Set(&box1.pos, -5., -0.1, 0.); | |
86 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
87 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
88 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
89 | for (i = 0; i < 100; i++){ | |
90 | res = ccdGJKIntersect(&box1, &box2, &ccd); | |
91 | ||
92 | if (i < 35 || i > 65){ | |
93 | assertFalse(res); | |
94 | }else if (i != 35 && i != 65){ | |
95 | assertTrue(res); | |
96 | } | |
97 | ||
98 | box1.pos.v[0] += 0.1; | |
99 | } | |
100 | } | |
101 | ||
102 | TEST(boxboxAlignedY) | |
103 | { | |
104 | size_t i; | |
105 | ccd_t ccd; | |
106 | CCD_BOX(box1); | |
107 | CCD_BOX(box2); | |
108 | int res; | |
109 | ||
110 | CCD_INIT(&ccd); | |
111 | ccd.support1 = ccdSupport; | |
112 | ccd.support2 = ccdSupport; | |
113 | ||
114 | box1.x = 1; | |
115 | box1.y = 2; | |
116 | box1.z = 1; | |
117 | box2.x = 2; | |
118 | box2.y = 1; | |
119 | box2.z = 2; | |
120 | ||
121 | ccdVec3Set(&box1.pos, 0., -5., 0.); | |
122 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
123 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
124 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
125 | for (i = 0; i < 100; i++){ | |
126 | res = ccdGJKIntersect(&box1, &box2, &ccd); | |
127 | ||
128 | if (i < 35 || i > 65){ | |
129 | assertFalse(res); | |
130 | }else if (i != 35 && i != 65){ | |
131 | assertTrue(res); | |
132 | } | |
133 | ||
134 | box1.pos.v[1] += 0.1; | |
135 | } | |
136 | } | |
137 | ||
138 | TEST(boxboxAlignedZ) | |
139 | { | |
140 | size_t i; | |
141 | ccd_t ccd; | |
142 | CCD_BOX(box1); | |
143 | CCD_BOX(box2); | |
144 | int res; | |
145 | ||
146 | CCD_INIT(&ccd); | |
147 | ccd.support1 = ccdSupport; | |
148 | ccd.support2 = ccdSupport; | |
149 | ||
150 | box1.x = 1; | |
151 | box1.y = 2; | |
152 | box1.z = 1; | |
153 | box2.x = 2; | |
154 | box2.y = 1; | |
155 | box2.z = 2; | |
156 | ||
157 | ccdVec3Set(&box1.pos, 0., 0., -5.); | |
158 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
159 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
160 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
161 | for (i = 0; i < 100; i++){ | |
162 | res = ccdGJKIntersect(&box1, &box2, &ccd); | |
163 | ||
164 | if (i < 35 || i > 65){ | |
165 | assertFalse(res); | |
166 | }else if (i != 35 && i != 65){ | |
167 | assertTrue(res); | |
168 | } | |
169 | ||
170 | box1.pos.v[2] += 0.1; | |
171 | } | |
172 | } | |
173 | ||
174 | ||
175 | TEST(boxboxRot) | |
176 | { | |
177 | size_t i; | |
178 | ccd_t ccd; | |
179 | CCD_BOX(box1); | |
180 | CCD_BOX(box2); | |
181 | int res; | |
182 | ccd_vec3_t axis; | |
183 | ccd_real_t angle; | |
184 | ||
185 | CCD_INIT(&ccd); | |
186 | ccd.support1 = ccdSupport; | |
187 | ccd.support2 = ccdSupport; | |
188 | ||
189 | box1.x = 1; | |
190 | box1.y = 2; | |
191 | box1.z = 1; | |
192 | box2.x = 2; | |
193 | box2.y = 1; | |
194 | box2.z = 2; | |
195 | ||
196 | ccdVec3Set(&box1.pos, -5., 0.5, 0.); | |
197 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
198 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
199 | ccdVec3Set(&axis, 0., 1., 0.); | |
200 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
201 | ||
202 | for (i = 0; i < 100; i++){ | |
203 | res = ccdGJKIntersect(&box1, &box2, &ccd); | |
204 | ||
205 | if (i < 33 || i > 67){ | |
206 | assertFalse(res); | |
207 | }else if (i != 33 && i != 67){ | |
208 | assertTrue(res); | |
209 | } | |
210 | ||
211 | box1.pos.v[0] += 0.1; | |
212 | } | |
213 | ||
214 | box1.x = 1; | |
215 | box1.y = 1; | |
216 | box1.z = 1; | |
217 | box2.x = 1; | |
218 | box2.y = 1; | |
219 | box2.z = 1; | |
220 | ||
221 | ccdVec3Set(&box1.pos, -1.01, 0., 0.); | |
222 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
223 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
224 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
225 | ||
226 | ccdVec3Set(&axis, 0., 1., 0.); | |
227 | angle = 0.; | |
228 | for (i = 0; i < 30; i++){ | |
229 | res = ccdGJKIntersect(&box1, &box2, &ccd); | |
230 | ||
231 | if (i != 0 && i != 10 && i != 20){ | |
232 | assertTrue(res); | |
233 | }else{ | |
234 | assertFalse(res); | |
235 | } | |
236 | ||
237 | angle += M_PI / 20.; | |
238 | ccdQuatSetAngleAxis(&box1.quat, angle, &axis); | |
239 | } | |
240 | ||
241 | } | |
242 | ||
243 | ||
244 | ||
245 | static void pConf(ccd_box_t *box1, ccd_box_t *box2, const ccd_vec3_t *v) | |
246 | { | |
247 | fprintf(stdout, "# box1.pos: [%lf %lf %lf]\n", | |
248 | ccdVec3X(&box1->pos), ccdVec3Y(&box1->pos), ccdVec3Z(&box1->pos)); | |
249 | fprintf(stdout, "# box1->quat: [%lf %lf %lf %lf]\n", | |
250 | box1->quat.q[0], box1->quat.q[1], box1->quat.q[2], box1->quat.q[3]); | |
251 | fprintf(stdout, "# box2->pos: [%lf %lf %lf]\n", | |
252 | ccdVec3X(&box2->pos), ccdVec3Y(&box2->pos), ccdVec3Z(&box2->pos)); | |
253 | fprintf(stdout, "# box2->quat: [%lf %lf %lf %lf]\n", | |
254 | box2->quat.q[0], box2->quat.q[1], box2->quat.q[2], box2->quat.q[3]); | |
255 | fprintf(stdout, "# sep: [%lf %lf %lf]\n", | |
256 | ccdVec3X(v), ccdVec3Y(v), ccdVec3Z(v)); | |
257 | fprintf(stdout, "#\n"); | |
258 | } | |
259 | ||
260 | TEST(boxboxSeparate) | |
261 | { | |
262 | ccd_t ccd; | |
263 | CCD_BOX(box1); | |
264 | CCD_BOX(box2); | |
265 | int res; | |
266 | ccd_vec3_t sep, expsep, expsep2, axis; | |
267 | ||
268 | fprintf(stderr, "\n\n\n---- boxboxSeparate ----\n\n\n"); | |
269 | ||
270 | box1.x = box1.y = box1.z = 1.; | |
271 | box2.x = 0.5; | |
272 | box2.y = 1.; | |
273 | box2.z = 1.5; | |
274 | ||
275 | ||
276 | CCD_INIT(&ccd); | |
277 | ccd.support1 = ccdSupport; | |
278 | ccd.support2 = ccdSupport; | |
279 | ||
280 | ccdVec3Set(&box1.pos, -0.5, 0.5, 0.2); | |
281 | res = ccdGJKIntersect(&box1, &box2, &ccd); | |
282 | assertTrue(res); | |
283 | ||
284 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
285 | assertTrue(res == 0); | |
286 | ccdVec3Set(&expsep, 0.25, 0., 0.); | |
287 | assertTrue(ccdVec3Eq(&sep, &expsep)); | |
288 | ||
289 | ccdVec3Scale(&sep, -1.); | |
290 | ccdVec3Add(&box1.pos, &sep); | |
291 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
292 | assertTrue(res == 0); | |
293 | ccdVec3Set(&expsep, 0., 0., 0.); | |
294 | assertTrue(ccdVec3Eq(&sep, &expsep)); | |
295 | ||
296 | ||
297 | ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); | |
298 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
299 | assertTrue(res == 0); | |
300 | ccdVec3Set(&expsep, 0., 0., -0.25); | |
301 | assertTrue(ccdVec3Eq(&sep, &expsep)); | |
302 | ||
303 | ||
304 | ||
305 | box1.x = box1.y = box1.z = 1.; | |
306 | box2.x = box2.y = box2.z = 1.; | |
307 | ccdVec3Set(&axis, 0., 0., 1.); | |
308 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
309 | ccdVec3Set(&box1.pos, 0., 0., 0.); | |
310 | ||
311 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
312 | assertTrue(res == 0); | |
313 | ccdVec3Set(&expsep, 0., 0., 1.); | |
314 | ccdVec3Set(&expsep2, 0., 0., -1.); | |
315 | assertTrue(ccdVec3Eq(&sep, &expsep) || ccdVec3Eq(&sep, &expsep2)); | |
316 | ||
317 | ||
318 | ||
319 | box1.x = box1.y = box1.z = 1.; | |
320 | ccdVec3Set(&axis, 0., 0., 1.); | |
321 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
322 | ccdVec3Set(&box1.pos, -0.5, 0., 0.); | |
323 | ||
324 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
325 | assertTrue(res == 0); | |
326 | pConf(&box1, &box2, &sep); | |
327 | ||
328 | ||
329 | ||
330 | box1.x = box1.y = box1.z = 1.; | |
331 | ccdVec3Set(&axis, 0., 1., 1.); | |
332 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
333 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
334 | ||
335 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
336 | assertTrue(res == 0); | |
337 | pConf(&box1, &box2, &sep); | |
338 | } | |
339 | ||
340 | ||
341 | #define TOSVT() \ | |
342 | svtObjPen(&box1, &box2, stdout, "Pen 1", depth, &dir, &pos); \ | |
343 | ccdVec3Scale(&dir, depth); \ | |
344 | ccdVec3Add(&box2.pos, &dir); \ | |
345 | svtObjPen(&box1, &box2, stdout, "Pen 1", depth, &dir, &pos) | |
346 | ||
347 | TEST(boxboxPenetration) | |
348 | { | |
349 | ccd_t ccd; | |
350 | CCD_BOX(box1); | |
351 | CCD_BOX(box2); | |
352 | int res; | |
353 | ccd_vec3_t axis; | |
354 | ccd_quat_t rot; | |
355 | ccd_real_t depth; | |
356 | ccd_vec3_t dir, pos; | |
357 | ||
358 | fprintf(stderr, "\n\n\n---- boxboxPenetration ----\n\n\n"); | |
359 | ||
360 | box1.x = box1.y = box1.z = 1.; | |
361 | box2.x = 0.5; | |
362 | box2.y = 1.; | |
363 | box2.z = 1.5; | |
364 | ||
365 | ||
366 | CCD_INIT(&ccd); | |
367 | ccd.support1 = ccdSupport; | |
368 | ccd.support2 = ccdSupport; | |
369 | ||
370 | ccdVec3Set(&box2.pos, 0.1, 0., 0.); | |
371 | res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
372 | assertTrue(res == 0); | |
373 | recPen(depth, &dir, &pos, stdout, "Pen 1"); | |
374 | //TOSVT(); | |
375 | ||
376 | ||
377 | ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); | |
378 | res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
379 | assertTrue(res == 0); | |
380 | recPen(depth, &dir, &pos, stdout, "Pen 2"); | |
381 | //TOSVT(); <<< | |
382 | ||
383 | ||
384 | box1.x = box1.y = box1.z = 1.; | |
385 | box2.x = box2.y = box2.z = 1.; | |
386 | ccdVec3Set(&axis, 0., 0., 1.); | |
387 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
388 | ccdVec3Set(&box1.pos, 0.1, 0., 0.1); | |
389 | ||
390 | res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
391 | assertTrue(res == 0); | |
392 | recPen(depth, &dir, &pos, stdout, "Pen 3"); | |
393 | //TOSVT(); | |
394 | ||
395 | ||
396 | box1.x = box1.y = box1.z = 1.; | |
397 | box2.x = box2.y = box2.z = 1.; | |
398 | ccdVec3Set(&axis, 0., 0., 1.); | |
399 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
400 | ccdVec3Set(&box1.pos, -0.5, 0., 0.); | |
401 | ||
402 | res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
403 | assertTrue(res == 0); | |
404 | recPen(depth, &dir, &pos, stdout, "Pen 4"); | |
405 | //TOSVT(); | |
406 | ||
407 | ||
408 | box1.x = box1.y = box1.z = 1.; | |
409 | box2.x = box2.y = box2.z = 1.; | |
410 | ccdVec3Set(&axis, 0., 0., 1.); | |
411 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
412 | ccdVec3Set(&box1.pos, -0.5, 0.5, 0.); | |
413 | ||
414 | res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
415 | assertTrue(res == 0); | |
416 | recPen(depth, &dir, &pos, stdout, "Pen 5"); | |
417 | //TOSVT(); | |
418 | ||
419 | ||
420 | box1.x = box1.y = box1.z = 1.; | |
421 | box2.x = box2.y = box2.z = 1.; | |
422 | ccdVec3Set(&box2.pos, 0.1, 0., 0.); | |
423 | ||
424 | box1.x = box1.y = box1.z = 1.; | |
425 | ccdVec3Set(&axis, 0., 1., 1.); | |
426 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
427 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
428 | ||
429 | res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
430 | assertTrue(res == 0); | |
431 | recPen(depth, &dir, &pos, stdout, "Pen 6"); | |
432 | //TOSVT(); | |
433 | ||
434 | ||
435 | box1.x = box1.y = box1.z = 1.; | |
436 | ccdVec3Set(&axis, 0., 1., 1.); | |
437 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
438 | ccdVec3Set(&axis, 1., 1., 1.); | |
439 | ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); | |
440 | ccdQuatMul(&box1.quat, &rot); | |
441 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
442 | ||
443 | res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
444 | assertTrue(res == 0); | |
445 | recPen(depth, &dir, &pos, stdout, "Pen 7"); | |
446 | //TOSVT(); <<< | |
447 | ||
448 | ||
449 | box1.x = box1.y = box1.z = 1.; | |
450 | box2.x = 0.2; box2.y = 0.5; box2.z = 1.; | |
451 | box2.x = box2.y = box2.z = 1.; | |
452 | ||
453 | ccdVec3Set(&axis, 0., 0., 1.); | |
454 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
455 | ccdVec3Set(&axis, 1., 0., 0.); | |
456 | ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); | |
457 | ccdQuatMul(&box1.quat, &rot); | |
458 | ccdVec3Set(&box1.pos, -1.3, 0., 0.); | |
459 | ||
460 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
461 | ||
462 | res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
463 | assertTrue(res == 0); | |
464 | recPen(depth, &dir, &pos, stdout, "Pen 8"); | |
465 | //TOSVT(); | |
466 | } |
0 | #ifndef BOX_BOX | |
1 | #define BOX_BOX | |
2 | ||
3 | #include <cu/cu.h> | |
4 | ||
5 | TEST(boxboxSetUp); | |
6 | TEST(boxboxTearDown); | |
7 | ||
8 | TEST(boxboxAlignedX); | |
9 | TEST(boxboxAlignedY); | |
10 | TEST(boxboxAlignedZ); | |
11 | ||
12 | TEST(boxboxRot); | |
13 | ||
14 | TEST(boxboxSeparate); | |
15 | TEST(boxboxPenetration); | |
16 | ||
17 | TEST_SUITE(TSBoxBox) { | |
18 | TEST_ADD(boxboxSetUp), | |
19 | ||
20 | TEST_ADD(boxboxAlignedX), | |
21 | TEST_ADD(boxboxAlignedY), | |
22 | TEST_ADD(boxboxAlignedZ), | |
23 | TEST_ADD(boxboxRot), | |
24 | TEST_ADD(boxboxSeparate), | |
25 | TEST_ADD(boxboxPenetration), | |
26 | ||
27 | TEST_ADD(boxboxTearDown), | |
28 | TEST_SUITE_CLOSURE | |
29 | }; | |
30 | ||
31 | #endif |
0 | #include <cu/cu.h> | |
1 | #include "common.h" | |
2 | #include <ccd/ccd.h> | |
3 | #include "support.h" | |
4 | ||
5 | ||
6 | #define TOSVT() \ | |
7 | svtObjPen(&box, &cyl, stdout, "Pen 1", depth, &dir, &pos); \ | |
8 | ccdVec3Scale(&dir, depth); \ | |
9 | ccdVec3Add(&cyl.pos, &dir); \ | |
10 | svtObjPen(&box, &cyl, stdout, "Pen 1", depth, &dir, &pos) | |
11 | ||
12 | ||
13 | TEST(boxcylIntersect) | |
14 | { | |
15 | ccd_t ccd; | |
16 | CCD_BOX(box); | |
17 | CCD_CYL(cyl); | |
18 | int res; | |
19 | ccd_vec3_t axis; | |
20 | ||
21 | box.x = 0.5; | |
22 | box.y = 1.; | |
23 | box.z = 1.5; | |
24 | cyl.radius = 0.4; | |
25 | cyl.height = 0.7; | |
26 | ||
27 | CCD_INIT(&ccd); | |
28 | ccd.support1 = ccdSupport; | |
29 | ccd.support2 = ccdSupport; | |
30 | ||
31 | ccdVec3Set(&cyl.pos, 0.1, 0., 0.); | |
32 | res = ccdGJKIntersect(&box, &cyl, &ccd); | |
33 | assertTrue(res); | |
34 | ||
35 | ccdVec3Set(&cyl.pos, .6, 0., 0.); | |
36 | res = ccdGJKIntersect(&box, &cyl, &ccd); | |
37 | assertTrue(res); | |
38 | ||
39 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.); | |
40 | res = ccdGJKIntersect(&box, &cyl, &ccd); | |
41 | assertTrue(res); | |
42 | ||
43 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
44 | res = ccdGJKIntersect(&box, &cyl, &ccd); | |
45 | assertTrue(res); | |
46 | ||
47 | ccdVec3Set(&axis, 0., 1., 0.); | |
48 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); | |
49 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
50 | res = ccdGJKIntersect(&box, &cyl, &ccd); | |
51 | assertTrue(res); | |
52 | ||
53 | ccdVec3Set(&axis, 0.67, 1.1, 0.12); | |
54 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); | |
55 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
56 | res = ccdGJKIntersect(&box, &cyl, &ccd); | |
57 | assertTrue(res); | |
58 | ||
59 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
60 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
61 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
62 | ccdVec3Set(&axis, 1., 1., 0.); | |
63 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
64 | ccdVec3Set(&box.pos, .6, 0., 0.5); | |
65 | res = ccdGJKIntersect(&box, &cyl, &ccd); | |
66 | assertTrue(res); | |
67 | ||
68 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
69 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
70 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
71 | ccdVec3Set(&axis, 1., 1., 0.); | |
72 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
73 | ccdVec3Set(&box.pos, .9, 0.8, 0.5); | |
74 | res = ccdGJKIntersect(&box, &cyl, &ccd); | |
75 | assertTrue(res); | |
76 | } | |
77 | ||
78 | ||
79 | TEST(boxcylPenEPA) | |
80 | { | |
81 | ccd_t ccd; | |
82 | CCD_BOX(box); | |
83 | CCD_CYL(cyl); | |
84 | int res; | |
85 | ccd_vec3_t axis; | |
86 | ccd_real_t depth; | |
87 | ccd_vec3_t dir, pos; | |
88 | ||
89 | box.x = 0.5; | |
90 | box.y = 1.; | |
91 | box.z = 1.5; | |
92 | cyl.radius = 0.4; | |
93 | cyl.height = 0.7; | |
94 | ||
95 | CCD_INIT(&ccd); | |
96 | ccd.support1 = ccdSupport; | |
97 | ccd.support2 = ccdSupport; | |
98 | ||
99 | ccdVec3Set(&cyl.pos, 0.1, 0., 0.); | |
100 | res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
101 | assertTrue(res == 0); | |
102 | recPen(depth, &dir, &pos, stdout, "Pen 1"); | |
103 | //TOSVT(); | |
104 | ||
105 | ccdVec3Set(&cyl.pos, .6, 0., 0.); | |
106 | res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
107 | assertTrue(res == 0); | |
108 | recPen(depth, &dir, &pos, stdout, "Pen 2"); | |
109 | //TOSVT(); <<< | |
110 | ||
111 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.); | |
112 | res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
113 | assertTrue(res == 0); | |
114 | recPen(depth, &dir, &pos, stdout, "Pen 3"); | |
115 | //TOSVT(); | |
116 | ||
117 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
118 | res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
119 | assertTrue(res == 0); | |
120 | recPen(depth, &dir, &pos, stdout, "Pen 4"); | |
121 | //TOSVT(); | |
122 | ||
123 | ccdVec3Set(&axis, 0., 1., 0.); | |
124 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); | |
125 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
126 | res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
127 | assertTrue(res == 0); | |
128 | recPen(depth, &dir, &pos, stdout, "Pen 5"); | |
129 | //TOSVT(); | |
130 | ||
131 | ccdVec3Set(&axis, 0.67, 1.1, 0.12); | |
132 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); | |
133 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
134 | res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
135 | assertTrue(res == 0); | |
136 | recPen(depth, &dir, &pos, stdout, "Pen 6"); | |
137 | //TOSVT(); | |
138 | ||
139 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
140 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
141 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
142 | ccdVec3Set(&axis, 1., 1., 0.); | |
143 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
144 | ccdVec3Set(&box.pos, .6, 0., 0.5); | |
145 | res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
146 | assertTrue(res == 0); | |
147 | recPen(depth, &dir, &pos, stdout, "Pen 7"); | |
148 | //TOSVT(); | |
149 | ||
150 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
151 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
152 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
153 | ccdVec3Set(&axis, 1., 1., 0.); | |
154 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
155 | ccdVec3Set(&box.pos, .9, 0.8, 0.5); | |
156 | res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
157 | assertTrue(res == 0); | |
158 | recPen(depth, &dir, &pos, stdout, "Pen 8"); | |
159 | //TOSVT(); | |
160 | } | |
161 |
0 | #ifndef TEST_BOXCYL_H | |
1 | #define TEST_BOXCYL_H | |
2 | ||
3 | #include <cu/cu.h> | |
4 | ||
5 | TEST(boxcylIntersect); | |
6 | TEST(boxcylPenEPA); | |
7 | ||
8 | TEST_SUITE(TSBoxCyl){ | |
9 | TEST_ADD(boxcylIntersect), | |
10 | TEST_ADD(boxcylPenEPA), | |
11 | ||
12 | TEST_SUITE_CLOSURE | |
13 | }; | |
14 | ||
15 | #endif |
0 | #include "common.h" | |
1 | #include <ccd/vec3.h> | |
2 | #include <ccd/quat.h> | |
3 | #include "support.h" | |
4 | ||
5 | static void svtCyl(ccd_cyl_t *c, FILE *out, const char *color, const char *name) | |
6 | { | |
7 | ccd_vec3_t v[32]; | |
8 | ccd_quat_t rot; | |
9 | ccd_vec3_t axis, vpos, vpos2; | |
10 | ccd_real_t angle, x, y; | |
11 | int i; | |
12 | ||
13 | ccdVec3Set(&axis, 0., 0., 1.); | |
14 | ccdVec3Set(&vpos, 0., c->radius, 0.); | |
15 | angle = 0.; | |
16 | for (i = 0; i < 16; i++){ | |
17 | angle = (ccd_real_t)i * (2. * M_PI / 16.); | |
18 | ||
19 | ccdQuatSetAngleAxis(&rot, angle, &axis); | |
20 | ccdVec3Copy(&vpos2, &vpos); | |
21 | ccdQuatRotVec(&vpos2, &rot); | |
22 | x = ccdVec3X(&vpos2); | |
23 | y = ccdVec3Y(&vpos2); | |
24 | ||
25 | ccdVec3Set(&v[i], x, y, c->height / 2.); | |
26 | ccdVec3Set(&v[i + 16], x, y, -c->height / 2.); | |
27 | } | |
28 | ||
29 | for (i = 0; i < 32; i++){ | |
30 | ccdQuatRotVec(&v[i], &c->quat); | |
31 | ccdVec3Add(&v[i], &c->pos); | |
32 | } | |
33 | ||
34 | fprintf(out, "-----\n"); | |
35 | if (name) | |
36 | fprintf(out, "Name: %s\n", name); | |
37 | ||
38 | fprintf(out, "Face color: %s\n", color); | |
39 | fprintf(out, "Edge color: %s\n", color); | |
40 | fprintf(out, "Point color: %s\n", color); | |
41 | fprintf(out, "Points:\n"); | |
42 | for (i = 0; i < 32; i++){ | |
43 | fprintf(out, "%lf %lf %lf\n", ccdVec3X(&v[i]), ccdVec3Y(&v[i]), ccdVec3Z(&v[i])); | |
44 | } | |
45 | ||
46 | fprintf(out, "Edges:\n"); | |
47 | fprintf(out, "0 16\n"); | |
48 | fprintf(out, "0 31\n"); | |
49 | for (i = 1; i < 16; i++){ | |
50 | fprintf(out, "0 %d\n", i); | |
51 | fprintf(out, "16 %d\n", i + 16); | |
52 | if (i != 0){ | |
53 | fprintf(out, "%d %d\n", i - 1, i); | |
54 | fprintf(out, "%d %d\n", i + 16 - 1, i + 16); | |
55 | } | |
56 | ||
57 | fprintf(out, "%d %d\n", i, i + 16); | |
58 | fprintf(out, "%d %d\n", i, i + 16 - 1); | |
59 | } | |
60 | ||
61 | fprintf(out, "Faces:\n"); | |
62 | for (i = 2; i < 16; i++){ | |
63 | fprintf(out, "0 %d %d\n", i, i -1); | |
64 | fprintf(out, "16 %d %d\n", i + 16, i + 16 -1); | |
65 | ||
66 | } | |
67 | fprintf(out, "0 16 31\n"); | |
68 | fprintf(out, "0 31 15\n"); | |
69 | for (i = 1; i < 16; i++){ | |
70 | fprintf(out, "%d %d %d\n", i, i + 16, i + 16 - 1); | |
71 | fprintf(out, "%d %d %d\n", i, i + 16 - 1, i - 1); | |
72 | } | |
73 | fprintf(out, "-----\n"); | |
74 | } | |
75 | ||
76 | static void svtBox(ccd_box_t *b, FILE *out, const char *color, const char *name) | |
77 | { | |
78 | ccd_vec3_t v[8]; | |
79 | size_t i; | |
80 | ||
81 | ccdVec3Set(&v[0], b->x * 0.5, b->y * 0.5, b->z * 0.5); | |
82 | ccdVec3Set(&v[1], b->x * 0.5, b->y * -0.5, b->z * 0.5); | |
83 | ccdVec3Set(&v[2], b->x * 0.5, b->y * 0.5, b->z * -0.5); | |
84 | ccdVec3Set(&v[3], b->x * 0.5, b->y * -0.5, b->z * -0.5); | |
85 | ccdVec3Set(&v[4], b->x * -0.5, b->y * 0.5, b->z * 0.5); | |
86 | ccdVec3Set(&v[5], b->x * -0.5, b->y * -0.5, b->z * 0.5); | |
87 | ccdVec3Set(&v[6], b->x * -0.5, b->y * 0.5, b->z * -0.5); | |
88 | ccdVec3Set(&v[7], b->x * -0.5, b->y * -0.5, b->z * -0.5); | |
89 | ||
90 | for (i = 0; i < 8; i++){ | |
91 | ccdQuatRotVec(&v[i], &b->quat); | |
92 | ccdVec3Add(&v[i], &b->pos); | |
93 | } | |
94 | ||
95 | fprintf(out, "-----\n"); | |
96 | if (name) | |
97 | fprintf(out, "Name: %s\n", name); | |
98 | fprintf(out, "Face color: %s\n", color); | |
99 | fprintf(out, "Edge color: %s\n", color); | |
100 | fprintf(out, "Point color: %s\n", color); | |
101 | fprintf(out, "Points:\n"); | |
102 | for (i = 0; i < 8; i++){ | |
103 | fprintf(out, "%lf %lf %lf\n", ccdVec3X(&v[i]), ccdVec3Y(&v[i]), ccdVec3Z(&v[i])); | |
104 | } | |
105 | ||
106 | fprintf(out, "Edges:\n"); | |
107 | fprintf(out, "0 1\n 0 2\n2 3\n3 1\n1 2\n6 2\n1 7\n1 5\n"); | |
108 | fprintf(out, "5 0\n0 4\n4 2\n6 4\n6 5\n5 7\n6 7\n7 2\n7 3\n4 5\n"); | |
109 | ||
110 | fprintf(out, "Faces:\n"); | |
111 | fprintf(out, "0 2 1\n1 2 3\n6 2 4\n4 2 0\n4 0 5\n5 0 1\n"); | |
112 | fprintf(out, "5 1 7\n7 1 3\n6 4 5\n6 5 7\n2 6 7\n2 7 3\n"); | |
113 | fprintf(out, "-----\n"); | |
114 | } | |
115 | ||
116 | ||
117 | void svtObj(void *_o, FILE *out, const char *color, const char *name) | |
118 | { | |
119 | ccd_obj_t *o = (ccd_obj_t *)_o; | |
120 | ||
121 | if (o->type == CCD_OBJ_CYL){ | |
122 | svtCyl((ccd_cyl_t *)o, out, color, name); | |
123 | }else if (o->type == CCD_OBJ_BOX){ | |
124 | svtBox((ccd_box_t *)o, out, color, name); | |
125 | } | |
126 | } | |
127 | ||
128 | void svtObjPen(void *o1, void *o2, | |
129 | FILE *out, const char *name, | |
130 | ccd_real_t depth, const ccd_vec3_t *dir, const ccd_vec3_t *pos) | |
131 | { | |
132 | ccd_vec3_t sep; | |
133 | char oname[500]; | |
134 | ||
135 | ccdVec3Copy(&sep, dir); | |
136 | ccdVec3Scale(&sep, depth); | |
137 | ccdVec3Add(&sep, pos); | |
138 | ||
139 | fprintf(out, "------\n"); | |
140 | if (name) | |
141 | fprintf(out, "Name: %s\n", name); | |
142 | fprintf(out, "Point color: 0.1 0.1 0.9\n"); | |
143 | fprintf(out, "Points:\n%lf %lf %lf\n", ccdVec3X(pos), ccdVec3Y(pos), ccdVec3Z(pos)); | |
144 | fprintf(out, "------\n"); | |
145 | fprintf(out, "Point color: 0.1 0.9 0.9\n"); | |
146 | fprintf(out, "Edge color: 0.1 0.9 0.9\n"); | |
147 | fprintf(out, "Points:\n%lf %lf %lf\n", ccdVec3X(pos), ccdVec3Y(pos), ccdVec3Z(pos)); | |
148 | fprintf(out, "%lf %lf %lf\n", ccdVec3X(&sep), ccdVec3Y(&sep), ccdVec3Z(&sep)); | |
149 | fprintf(out, "Edges: 0 1\n"); | |
150 | ||
151 | oname[0] = 0x0; | |
152 | if (name) | |
153 | sprintf(oname, "%s o1", name); | |
154 | svtObj(o1, out, "0.9 0.1 0.1", oname); | |
155 | ||
156 | oname[0] = 0x0; | |
157 | if (name) | |
158 | sprintf(oname, "%s o1", name); | |
159 | svtObj(o2, out, "0.1 0.9 0.1", oname); | |
160 | } | |
161 | ||
162 | ||
163 | void recPen(ccd_real_t depth, const ccd_vec3_t *dir, const ccd_vec3_t *pos, | |
164 | FILE *out, const char *note) | |
165 | { | |
166 | if (!note) | |
167 | note = ""; | |
168 | ||
169 | fprintf(out, "# %s: depth: %lf\n", note, depth); | |
170 | fprintf(out, "# %s: dir: [%lf %lf %lf]\n", note, ccdVec3X(dir), ccdVec3Y(dir), ccdVec3Z(dir)); | |
171 | fprintf(out, "# %s: pos: [%lf %lf %lf]\n", note, ccdVec3X(pos), ccdVec3Y(pos), ccdVec3Z(pos)); | |
172 | fprintf(out, "#\n"); | |
173 | } |
0 | #ifndef TEST_COMMON | |
1 | #define TEST_COMMON | |
2 | ||
3 | #include <stdio.h> | |
4 | #include <ccd/vec3.h> | |
5 | ||
6 | void svtObj(void *o, FILE *out, const char *color, const char *name); | |
7 | void svtObjPen(void *o1, void *o2, | |
8 | FILE *out, const char *name, | |
9 | ccd_real_t depth, const ccd_vec3_t *dir, const ccd_vec3_t *pos); | |
10 | void recPen(ccd_real_t depth, const ccd_vec3_t *dir, const ccd_vec3_t *pos, | |
11 | FILE *out, const char *note); | |
12 | ||
13 | #endif |
0 | GNU GENERAL PUBLIC LICENSE | |
1 | Version 3, 29 June 2007 | |
2 | ||
3 | Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | |
4 | Everyone is permitted to copy and distribute verbatim copies | |
5 | of this license document, but changing it is not allowed. | |
6 | ||
7 | Preamble | |
8 | ||
9 | The GNU General Public License is a free, copyleft license for | |
10 | software and other kinds of works. | |
11 | ||
12 | The licenses for most software and other practical works are designed | |
13 | to take away your freedom to share and change the works. By contrast, | |
14 | the GNU General Public License is intended to guarantee your freedom to | |
15 | share and change all versions of a program--to make sure it remains free | |
16 | software for all its users. We, the Free Software Foundation, use the | |
17 | GNU General Public License for most of our software; it applies also to | |
18 | any other work released this way by its authors. You can apply it to | |
19 | your programs, too. | |
20 | ||
21 | When we speak of free software, we are referring to freedom, not | |
22 | price. Our General Public Licenses are designed to make sure that you | |
23 | have the freedom to distribute copies of free software (and charge for | |
24 | them if you wish), that you receive source code or can get it if you | |
25 | want it, that you can change the software or use pieces of it in new | |
26 | free programs, and that you know you can do these things. | |
27 | ||
28 | To protect your rights, we need to prevent others from denying you | |
29 | these rights or asking you to surrender the rights. Therefore, you have | |
30 | certain responsibilities if you distribute copies of the software, or if | |
31 | you modify it: responsibilities to respect the freedom of others. | |
32 | ||
33 | For example, if you distribute copies of such a program, whether | |
34 | gratis or for a fee, you must pass on to the recipients the same | |
35 | freedoms that you received. You must make sure that they, too, receive | |
36 | or can get the source code. And you must show them these terms so they | |
37 | know their rights. | |
38 | ||
39 | Developers that use the GNU GPL protect your rights with two steps: | |
40 | (1) assert copyright on the software, and (2) offer you this License | |
41 | giving you legal permission to copy, distribute and/or modify it. | |
42 | ||
43 | For the developers' and authors' protection, the GPL clearly explains | |
44 | that there is no warranty for this free software. For both users' and | |
45 | authors' sake, the GPL requires that modified versions be marked as | |
46 | changed, so that their problems will not be attributed erroneously to | |
47 | authors of previous versions. | |
48 | ||
49 | Some devices are designed to deny users access to install or run | |
50 | modified versions of the software inside them, although the manufacturer | |
51 | can do so. This is fundamentally incompatible with the aim of | |
52 | protecting users' freedom to change the software. The systematic | |
53 | pattern of such abuse occurs in the area of products for individuals to | |
54 | use, which is precisely where it is most unacceptable. Therefore, we | |
55 | have designed this version of the GPL to prohibit the practice for those | |
56 | products. If such problems arise substantially in other domains, we | |
57 | stand ready to extend this provision to those domains in future versions | |
58 | of the GPL, as needed to protect the freedom of users. | |
59 | ||
60 | Finally, every program is threatened constantly by software patents. | |
61 | States should not allow patents to restrict development and use of | |
62 | software on general-purpose computers, but in those that do, we wish to | |
63 | avoid the special danger that patents applied to a free program could | |
64 | make it effectively proprietary. To prevent this, the GPL assures that | |
65 | patents cannot be used to render the program non-free. | |
66 | ||
67 | The precise terms and conditions for copying, distribution and | |
68 | modification follow. | |
69 | ||
70 | TERMS AND CONDITIONS | |
71 | ||
72 | 0. Definitions. | |
73 | ||
74 | "This License" refers to version 3 of the GNU General Public License. | |
75 | ||
76 | "Copyright" also means copyright-like laws that apply to other kinds of | |
77 | works, such as semiconductor masks. | |
78 | ||
79 | "The Program" refers to any copyrightable work licensed under this | |
80 | License. Each licensee is addressed as "you". "Licensees" and | |
81 | "recipients" may be individuals or organizations. | |
82 | ||
83 | To "modify" a work means to copy from or adapt all or part of the work | |
84 | in a fashion requiring copyright permission, other than the making of an | |
85 | exact copy. The resulting work is called a "modified version" of the | |
86 | earlier work or a work "based on" the earlier work. | |
87 | ||
88 | A "covered work" means either the unmodified Program or a work based | |
89 | on the Program. | |
90 | ||
91 | To "propagate" a work means to do anything with it that, without | |
92 | permission, would make you directly or secondarily liable for | |
93 | infringement under applicable copyright law, except executing it on a | |
94 | computer or modifying a private copy. Propagation includes copying, | |
95 | distribution (with or without modification), making available to the | |
96 | public, and in some countries other activities as well. | |
97 | ||
98 | To "convey" a work means any kind of propagation that enables other | |
99 | parties to make or receive copies. Mere interaction with a user through | |
100 | a computer network, with no transfer of a copy, is not conveying. | |
101 | ||
102 | An interactive user interface displays "Appropriate Legal Notices" | |
103 | to the extent that it includes a convenient and prominently visible | |
104 | feature that (1) displays an appropriate copyright notice, and (2) | |
105 | tells the user that there is no warranty for the work (except to the | |
106 | extent that warranties are provided), that licensees may convey the | |
107 | work under this License, and how to view a copy of this License. If | |
108 | the interface presents a list of user commands or options, such as a | |
109 | menu, a prominent item in the list meets this criterion. | |
110 | ||
111 | 1. Source Code. | |
112 | ||
113 | The "source code" for a work means the preferred form of the work | |
114 | for making modifications to it. "Object code" means any non-source | |
115 | form of a work. | |
116 | ||
117 | A "Standard Interface" means an interface that either is an official | |
118 | standard defined by a recognized standards body, or, in the case of | |
119 | interfaces specified for a particular programming language, one that | |
120 | is widely used among developers working in that language. | |
121 | ||
122 | The "System Libraries" of an executable work include anything, other | |
123 | than the work as a whole, that (a) is included in the normal form of | |
124 | packaging a Major Component, but which is not part of that Major | |
125 | Component, and (b) serves only to enable use of the work with that | |
126 | Major Component, or to implement a Standard Interface for which an | |
127 | implementation is available to the public in source code form. A | |
128 | "Major Component", in this context, means a major essential component | |
129 | (kernel, window system, and so on) of the specific operating system | |
130 | (if any) on which the executable work runs, or a compiler used to | |
131 | produce the work, or an object code interpreter used to run it. | |
132 | ||
133 | The "Corresponding Source" for a work in object code form means all | |
134 | the source code needed to generate, install, and (for an executable | |
135 | work) run the object code and to modify the work, including scripts to | |
136 | control those activities. However, it does not include the work's | |
137 | System Libraries, or general-purpose tools or generally available free | |
138 | programs which are used unmodified in performing those activities but | |
139 | which are not part of the work. For example, Corresponding Source | |
140 | includes interface definition files associated with source files for | |
141 | the work, and the source code for shared libraries and dynamically | |
142 | linked subprograms that the work is specifically designed to require, | |
143 | such as by intimate data communication or control flow between those | |
144 | subprograms and other parts of the work. | |
145 | ||
146 | The Corresponding Source need not include anything that users | |
147 | can regenerate automatically from other parts of the Corresponding | |
148 | Source. | |
149 | ||
150 | The Corresponding Source for a work in source code form is that | |
151 | same work. | |
152 | ||
153 | 2. Basic Permissions. | |
154 | ||
155 | All rights granted under this License are granted for the term of | |
156 | copyright on the Program, and are irrevocable provided the stated | |
157 | conditions are met. This License explicitly affirms your unlimited | |
158 | permission to run the unmodified Program. The output from running a | |
159 | covered work is covered by this License only if the output, given its | |
160 | content, constitutes a covered work. This License acknowledges your | |
161 | rights of fair use or other equivalent, as provided by copyright law. | |
162 | ||
163 | You may make, run and propagate covered works that you do not | |
164 | convey, without conditions so long as your license otherwise remains | |
165 | in force. You may convey covered works to others for the sole purpose | |
166 | of having them make modifications exclusively for you, or provide you | |
167 | with facilities for running those works, provided that you comply with | |
168 | the terms of this License in conveying all material for which you do | |
169 | not control copyright. Those thus making or running the covered works | |
170 | for you must do so exclusively on your behalf, under your direction | |
171 | and control, on terms that prohibit them from making any copies of | |
172 | your copyrighted material outside their relationship with you. | |
173 | ||
174 | Conveying under any other circumstances is permitted solely under | |
175 | the conditions stated below. Sublicensing is not allowed; section 10 | |
176 | makes it unnecessary. | |
177 | ||
178 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | |
179 | ||
180 | No covered work shall be deemed part of an effective technological | |
181 | measure under any applicable law fulfilling obligations under article | |
182 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or | |
183 | similar laws prohibiting or restricting circumvention of such | |
184 | measures. | |
185 | ||
186 | When you convey a covered work, you waive any legal power to forbid | |
187 | circumvention of technological measures to the extent such circumvention | |
188 | is effected by exercising rights under this License with respect to | |
189 | the covered work, and you disclaim any intention to limit operation or | |
190 | modification of the work as a means of enforcing, against the work's | |
191 | users, your or third parties' legal rights to forbid circumvention of | |
192 | technological measures. | |
193 | ||
194 | 4. Conveying Verbatim Copies. | |
195 | ||
196 | You may convey verbatim copies of the Program's source code as you | |
197 | receive it, in any medium, provided that you conspicuously and | |
198 | appropriately publish on each copy an appropriate copyright notice; | |
199 | keep intact all notices stating that this License and any | |
200 | non-permissive terms added in accord with section 7 apply to the code; | |
201 | keep intact all notices of the absence of any warranty; and give all | |
202 | recipients a copy of this License along with the Program. | |
203 | ||
204 | You may charge any price or no price for each copy that you convey, | |
205 | and you may offer support or warranty protection for a fee. | |
206 | ||
207 | 5. Conveying Modified Source Versions. | |
208 | ||
209 | You may convey a work based on the Program, or the modifications to | |
210 | produce it from the Program, in the form of source code under the | |
211 | terms of section 4, provided that you also meet all of these conditions: | |
212 | ||
213 | a) The work must carry prominent notices stating that you modified | |
214 | it, and giving a relevant date. | |
215 | ||
216 | b) The work must carry prominent notices stating that it is | |
217 | released under this License and any conditions added under section | |
218 | 7. This requirement modifies the requirement in section 4 to | |
219 | "keep intact all notices". | |
220 | ||
221 | c) You must license the entire work, as a whole, under this | |
222 | License to anyone who comes into possession of a copy. This | |
223 | License will therefore apply, along with any applicable section 7 | |
224 | additional terms, to the whole of the work, and all its parts, | |
225 | regardless of how they are packaged. This License gives no | |
226 | permission to license the work in any other way, but it does not | |
227 | invalidate such permission if you have separately received it. | |
228 | ||
229 | d) If the work has interactive user interfaces, each must display | |
230 | Appropriate Legal Notices; however, if the Program has interactive | |
231 | interfaces that do not display Appropriate Legal Notices, your | |
232 | work need not make them do so. | |
233 | ||
234 | A compilation of a covered work with other separate and independent | |
235 | works, which are not by their nature extensions of the covered work, | |
236 | and which are not combined with it such as to form a larger program, | |
237 | in or on a volume of a storage or distribution medium, is called an | |
238 | "aggregate" if the compilation and its resulting copyright are not | |
239 | used to limit the access or legal rights of the compilation's users | |
240 | beyond what the individual works permit. Inclusion of a covered work | |
241 | in an aggregate does not cause this License to apply to the other | |
242 | parts of the aggregate. | |
243 | ||
244 | 6. Conveying Non-Source Forms. | |
245 | ||
246 | You may convey a covered work in object code form under the terms | |
247 | of sections 4 and 5, provided that you also convey the | |
248 | machine-readable Corresponding Source under the terms of this License, | |
249 | in one of these ways: | |
250 | ||
251 | a) Convey the object code in, or embodied in, a physical product | |
252 | (including a physical distribution medium), accompanied by the | |
253 | Corresponding Source fixed on a durable physical medium | |
254 | customarily used for software interchange. | |
255 | ||
256 | b) Convey the object code in, or embodied in, a physical product | |
257 | (including a physical distribution medium), accompanied by a | |
258 | written offer, valid for at least three years and valid for as | |
259 | long as you offer spare parts or customer support for that product | |
260 | model, to give anyone who possesses the object code either (1) a | |
261 | copy of the Corresponding Source for all the software in the | |
262 | product that is covered by this License, on a durable physical | |
263 | medium customarily used for software interchange, for a price no | |
264 | more than your reasonable cost of physically performing this | |
265 | conveying of source, or (2) access to copy the | |
266 | Corresponding Source from a network server at no charge. | |
267 | ||
268 | c) Convey individual copies of the object code with a copy of the | |
269 | written offer to provide the Corresponding Source. This | |
270 | alternative is allowed only occasionally and noncommercially, and | |
271 | only if you received the object code with such an offer, in accord | |
272 | with subsection 6b. | |
273 | ||
274 | d) Convey the object code by offering access from a designated | |
275 | place (gratis or for a charge), and offer equivalent access to the | |
276 | Corresponding Source in the same way through the same place at no | |
277 | further charge. You need not require recipients to copy the | |
278 | Corresponding Source along with the object code. If the place to | |
279 | copy the object code is a network server, the Corresponding Source | |
280 | may be on a different server (operated by you or a third party) | |
281 | that supports equivalent copying facilities, provided you maintain | |
282 | clear directions next to the object code saying where to find the | |
283 | Corresponding Source. Regardless of what server hosts the | |
284 | Corresponding Source, you remain obligated to ensure that it is | |
285 | available for as long as needed to satisfy these requirements. | |
286 | ||
287 | e) Convey the object code using peer-to-peer transmission, provided | |
288 | you inform other peers where the object code and Corresponding | |
289 | Source of the work are being offered to the general public at no | |
290 | charge under subsection 6d. | |
291 | ||
292 | A separable portion of the object code, whose source code is excluded | |
293 | from the Corresponding Source as a System Library, need not be | |
294 | included in conveying the object code work. | |
295 | ||
296 | A "User Product" is either (1) a "consumer product", which means any | |
297 | tangible personal property which is normally used for personal, family, | |
298 | or household purposes, or (2) anything designed or sold for incorporation | |
299 | into a dwelling. In determining whether a product is a consumer product, | |
300 | doubtful cases shall be resolved in favor of coverage. For a particular | |
301 | product received by a particular user, "normally used" refers to a | |
302 | typical or common use of that class of product, regardless of the status | |
303 | of the particular user or of the way in which the particular user | |
304 | actually uses, or expects or is expected to use, the product. A product | |
305 | is a consumer product regardless of whether the product has substantial | |
306 | commercial, industrial or non-consumer uses, unless such uses represent | |
307 | the only significant mode of use of the product. | |
308 | ||
309 | "Installation Information" for a User Product means any methods, | |
310 | procedures, authorization keys, or other information required to install | |
311 | and execute modified versions of a covered work in that User Product from | |
312 | a modified version of its Corresponding Source. The information must | |
313 | suffice to ensure that the continued functioning of the modified object | |
314 | code is in no case prevented or interfered with solely because | |
315 | modification has been made. | |
316 | ||
317 | If you convey an object code work under this section in, or with, or | |
318 | specifically for use in, a User Product, and the conveying occurs as | |
319 | part of a transaction in which the right of possession and use of the | |
320 | User Product is transferred to the recipient in perpetuity or for a | |
321 | fixed term (regardless of how the transaction is characterized), the | |
322 | Corresponding Source conveyed under this section must be accompanied | |
323 | by the Installation Information. But this requirement does not apply | |
324 | if neither you nor any third party retains the ability to install | |
325 | modified object code on the User Product (for example, the work has | |
326 | been installed in ROM). | |
327 | ||
328 | The requirement to provide Installation Information does not include a | |
329 | requirement to continue to provide support service, warranty, or updates | |
330 | for a work that has been modified or installed by the recipient, or for | |
331 | the User Product in which it has been modified or installed. Access to a | |
332 | network may be denied when the modification itself materially and | |
333 | adversely affects the operation of the network or violates the rules and | |
334 | protocols for communication across the network. | |
335 | ||
336 | Corresponding Source conveyed, and Installation Information provided, | |
337 | in accord with this section must be in a format that is publicly | |
338 | documented (and with an implementation available to the public in | |
339 | source code form), and must require no special password or key for | |
340 | unpacking, reading or copying. | |
341 | ||
342 | 7. Additional Terms. | |
343 | ||
344 | "Additional permissions" are terms that supplement the terms of this | |
345 | License by making exceptions from one or more of its conditions. | |
346 | Additional permissions that are applicable to the entire Program shall | |
347 | be treated as though they were included in this License, to the extent | |
348 | that they are valid under applicable law. If additional permissions | |
349 | apply only to part of the Program, that part may be used separately | |
350 | under those permissions, but the entire Program remains governed by | |
351 | this License without regard to the additional permissions. | |
352 | ||
353 | When you convey a copy of a covered work, you may at your option | |
354 | remove any additional permissions from that copy, or from any part of | |
355 | it. (Additional permissions may be written to require their own | |
356 | removal in certain cases when you modify the work.) You may place | |
357 | additional permissions on material, added by you to a covered work, | |
358 | for which you have or can give appropriate copyright permission. | |
359 | ||
360 | Notwithstanding any other provision of this License, for material you | |
361 | add to a covered work, you may (if authorized by the copyright holders of | |
362 | that material) supplement the terms of this License with terms: | |
363 | ||
364 | a) Disclaiming warranty or limiting liability differently from the | |
365 | terms of sections 15 and 16 of this License; or | |
366 | ||
367 | b) Requiring preservation of specified reasonable legal notices or | |
368 | author attributions in that material or in the Appropriate Legal | |
369 | Notices displayed by works containing it; or | |
370 | ||
371 | c) Prohibiting misrepresentation of the origin of that material, or | |
372 | requiring that modified versions of such material be marked in | |
373 | reasonable ways as different from the original version; or | |
374 | ||
375 | d) Limiting the use for publicity purposes of names of licensors or | |
376 | authors of the material; or | |
377 | ||
378 | e) Declining to grant rights under trademark law for use of some | |
379 | trade names, trademarks, or service marks; or | |
380 | ||
381 | f) Requiring indemnification of licensors and authors of that | |
382 | material by anyone who conveys the material (or modified versions of | |
383 | it) with contractual assumptions of liability to the recipient, for | |
384 | any liability that these contractual assumptions directly impose on | |
385 | those licensors and authors. | |
386 | ||
387 | All other non-permissive additional terms are considered "further | |
388 | restrictions" within the meaning of section 10. If the Program as you | |
389 | received it, or any part of it, contains a notice stating that it is | |
390 | governed by this License along with a term that is a further | |
391 | restriction, you may remove that term. If a license document contains | |
392 | a further restriction but permits relicensing or conveying under this | |
393 | License, you may add to a covered work material governed by the terms | |
394 | of that license document, provided that the further restriction does | |
395 | not survive such relicensing or conveying. | |
396 | ||
397 | If you add terms to a covered work in accord with this section, you | |
398 | must place, in the relevant source files, a statement of the | |
399 | additional terms that apply to those files, or a notice indicating | |
400 | where to find the applicable terms. | |
401 | ||
402 | Additional terms, permissive or non-permissive, may be stated in the | |
403 | form of a separately written license, or stated as exceptions; | |
404 | the above requirements apply either way. | |
405 | ||
406 | 8. Termination. | |
407 | ||
408 | You may not propagate or modify a covered work except as expressly | |
409 | provided under this License. Any attempt otherwise to propagate or | |
410 | modify it is void, and will automatically terminate your rights under | |
411 | this License (including any patent licenses granted under the third | |
412 | paragraph of section 11). | |
413 | ||
414 | However, if you cease all violation of this License, then your | |
415 | license from a particular copyright holder is reinstated (a) | |
416 | provisionally, unless and until the copyright holder explicitly and | |
417 | finally terminates your license, and (b) permanently, if the copyright | |
418 | holder fails to notify you of the violation by some reasonable means | |
419 | prior to 60 days after the cessation. | |
420 | ||
421 | Moreover, your license from a particular copyright holder is | |
422 | reinstated permanently if the copyright holder notifies you of the | |
423 | violation by some reasonable means, this is the first time you have | |
424 | received notice of violation of this License (for any work) from that | |
425 | copyright holder, and you cure the violation prior to 30 days after | |
426 | your receipt of the notice. | |
427 | ||
428 | Termination of your rights under this section does not terminate the | |
429 | licenses of parties who have received copies or rights from you under | |
430 | this License. If your rights have been terminated and not permanently | |
431 | reinstated, you do not qualify to receive new licenses for the same | |
432 | material under section 10. | |
433 | ||
434 | 9. Acceptance Not Required for Having Copies. | |
435 | ||
436 | You are not required to accept this License in order to receive or | |
437 | run a copy of the Program. Ancillary propagation of a covered work | |
438 | occurring solely as a consequence of using peer-to-peer transmission | |
439 | to receive a copy likewise does not require acceptance. However, | |
440 | nothing other than this License grants you permission to propagate or | |
441 | modify any covered work. These actions infringe copyright if you do | |
442 | not accept this License. Therefore, by modifying or propagating a | |
443 | covered work, you indicate your acceptance of this License to do so. | |
444 | ||
445 | 10. Automatic Licensing of Downstream Recipients. | |
446 | ||
447 | Each time you convey a covered work, the recipient automatically | |
448 | receives a license from the original licensors, to run, modify and | |
449 | propagate that work, subject to this License. You are not responsible | |
450 | for enforcing compliance by third parties with this License. | |
451 | ||
452 | An "entity transaction" is a transaction transferring control of an | |
453 | organization, or substantially all assets of one, or subdividing an | |
454 | organization, or merging organizations. If propagation of a covered | |
455 | work results from an entity transaction, each party to that | |
456 | transaction who receives a copy of the work also receives whatever | |
457 | licenses to the work the party's predecessor in interest had or could | |
458 | give under the previous paragraph, plus a right to possession of the | |
459 | Corresponding Source of the work from the predecessor in interest, if | |
460 | the predecessor has it or can get it with reasonable efforts. | |
461 | ||
462 | You may not impose any further restrictions on the exercise of the | |
463 | rights granted or affirmed under this License. For example, you may | |
464 | not impose a license fee, royalty, or other charge for exercise of | |
465 | rights granted under this License, and you may not initiate litigation | |
466 | (including a cross-claim or counterclaim in a lawsuit) alleging that | |
467 | any patent claim is infringed by making, using, selling, offering for | |
468 | sale, or importing the Program or any portion of it. | |
469 | ||
470 | 11. Patents. | |
471 | ||
472 | A "contributor" is a copyright holder who authorizes use under this | |
473 | License of the Program or a work on which the Program is based. The | |
474 | work thus licensed is called the contributor's "contributor version". | |
475 | ||
476 | A contributor's "essential patent claims" are all patent claims | |
477 | owned or controlled by the contributor, whether already acquired or | |
478 | hereafter acquired, that would be infringed by some manner, permitted | |
479 | by this License, of making, using, or selling its contributor version, | |
480 | but do not include claims that would be infringed only as a | |
481 | consequence of further modification of the contributor version. For | |
482 | purposes of this definition, "control" includes the right to grant | |
483 | patent sublicenses in a manner consistent with the requirements of | |
484 | this License. | |
485 | ||
486 | Each contributor grants you a non-exclusive, worldwide, royalty-free | |
487 | patent license under the contributor's essential patent claims, to | |
488 | make, use, sell, offer for sale, import and otherwise run, modify and | |
489 | propagate the contents of its contributor version. | |
490 | ||
491 | In the following three paragraphs, a "patent license" is any express | |
492 | agreement or commitment, however denominated, not to enforce a patent | |
493 | (such as an express permission to practice a patent or covenant not to | |
494 | sue for patent infringement). To "grant" such a patent license to a | |
495 | party means to make such an agreement or commitment not to enforce a | |
496 | patent against the party. | |
497 | ||
498 | If you convey a covered work, knowingly relying on a patent license, | |
499 | and the Corresponding Source of the work is not available for anyone | |
500 | to copy, free of charge and under the terms of this License, through a | |
501 | publicly available network server or other readily accessible means, | |
502 | then you must either (1) cause the Corresponding Source to be so | |
503 | available, or (2) arrange to deprive yourself of the benefit of the | |
504 | patent license for this particular work, or (3) arrange, in a manner | |
505 | consistent with the requirements of this License, to extend the patent | |
506 | license to downstream recipients. "Knowingly relying" means you have | |
507 | actual knowledge that, but for the patent license, your conveying the | |
508 | covered work in a country, or your recipient's use of the covered work | |
509 | in a country, would infringe one or more identifiable patents in that | |
510 | country that you have reason to believe are valid. | |
511 | ||
512 | If, pursuant to or in connection with a single transaction or | |
513 | arrangement, you convey, or propagate by procuring conveyance of, a | |
514 | covered work, and grant a patent license to some of the parties | |
515 | receiving the covered work authorizing them to use, propagate, modify | |
516 | or convey a specific copy of the covered work, then the patent license | |
517 | you grant is automatically extended to all recipients of the covered | |
518 | work and works based on it. | |
519 | ||
520 | A patent license is "discriminatory" if it does not include within | |
521 | the scope of its coverage, prohibits the exercise of, or is | |
522 | conditioned on the non-exercise of one or more of the rights that are | |
523 | specifically granted under this License. You may not convey a covered | |
524 | work if you are a party to an arrangement with a third party that is | |
525 | in the business of distributing software, under which you make payment | |
526 | to the third party based on the extent of your activity of conveying | |
527 | the work, and under which the third party grants, to any of the | |
528 | parties who would receive the covered work from you, a discriminatory | |
529 | patent license (a) in connection with copies of the covered work | |
530 | conveyed by you (or copies made from those copies), or (b) primarily | |
531 | for and in connection with specific products or compilations that | |
532 | contain the covered work, unless you entered into that arrangement, | |
533 | or that patent license was granted, prior to 28 March 2007. | |
534 | ||
535 | Nothing in this License shall be construed as excluding or limiting | |
536 | any implied license or other defenses to infringement that may | |
537 | otherwise be available to you under applicable patent law. | |
538 | ||
539 | 12. No Surrender of Others' Freedom. | |
540 | ||
541 | If conditions are imposed on you (whether by court order, agreement or | |
542 | otherwise) that contradict the conditions of this License, they do not | |
543 | excuse you from the conditions of this License. If you cannot convey a | |
544 | covered work so as to satisfy simultaneously your obligations under this | |
545 | License and any other pertinent obligations, then as a consequence you may | |
546 | not convey it at all. For example, if you agree to terms that obligate you | |
547 | to collect a royalty for further conveying from those to whom you convey | |
548 | the Program, the only way you could satisfy both those terms and this | |
549 | License would be to refrain entirely from conveying the Program. | |
550 | ||
551 | 13. Use with the GNU Affero General Public License. | |
552 | ||
553 | Notwithstanding any other provision of this License, you have | |
554 | permission to link or combine any covered work with a work licensed | |
555 | under version 3 of the GNU Affero General Public License into a single | |
556 | combined work, and to convey the resulting work. The terms of this | |
557 | License will continue to apply to the part which is the covered work, | |
558 | but the special requirements of the GNU Affero General Public License, | |
559 | section 13, concerning interaction through a network will apply to the | |
560 | combination as such. | |
561 | ||
562 | 14. Revised Versions of this License. | |
563 | ||
564 | The Free Software Foundation may publish revised and/or new versions of | |
565 | the GNU General Public License from time to time. Such new versions will | |
566 | be similar in spirit to the present version, but may differ in detail to | |
567 | address new problems or concerns. | |
568 | ||
569 | Each version is given a distinguishing version number. If the | |
570 | Program specifies that a certain numbered version of the GNU General | |
571 | Public License "or any later version" applies to it, you have the | |
572 | option of following the terms and conditions either of that numbered | |
573 | version or of any later version published by the Free Software | |
574 | Foundation. If the Program does not specify a version number of the | |
575 | GNU General Public License, you may choose any version ever published | |
576 | by the Free Software Foundation. | |
577 | ||
578 | If the Program specifies that a proxy can decide which future | |
579 | versions of the GNU General Public License can be used, that proxy's | |
580 | public statement of acceptance of a version permanently authorizes you | |
581 | to choose that version for the Program. | |
582 | ||
583 | Later license versions may give you additional or different | |
584 | permissions. However, no additional obligations are imposed on any | |
585 | author or copyright holder as a result of your choosing to follow a | |
586 | later version. | |
587 | ||
588 | 15. Disclaimer of Warranty. | |
589 | ||
590 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | |
591 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | |
592 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | |
593 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | |
594 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
595 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | |
596 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | |
597 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |
598 | ||
599 | 16. Limitation of Liability. | |
600 | ||
601 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
602 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | |
603 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | |
604 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | |
605 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | |
606 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | |
607 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | |
608 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | |
609 | SUCH DAMAGES. | |
610 | ||
611 | 17. Interpretation of Sections 15 and 16. | |
612 | ||
613 | If the disclaimer of warranty and limitation of liability provided | |
614 | above cannot be given local legal effect according to their terms, | |
615 | reviewing courts shall apply local law that most closely approximates | |
616 | an absolute waiver of all civil liability in connection with the | |
617 | Program, unless a warranty or assumption of liability accompanies a | |
618 | copy of the Program in return for a fee. | |
619 | ||
620 | END OF TERMS AND CONDITIONS | |
621 | ||
622 | How to Apply These Terms to Your New Programs | |
623 | ||
624 | If you develop a new program, and you want it to be of the greatest | |
625 | possible use to the public, the best way to achieve this is to make it | |
626 | free software which everyone can redistribute and change under these terms. | |
627 | ||
628 | To do so, attach the following notices to the program. It is safest | |
629 | to attach them to the start of each source file to most effectively | |
630 | state the exclusion of warranty; and each file should have at least | |
631 | the "copyright" line and a pointer to where the full notice is found. | |
632 | ||
633 | <one line to give the program's name and a brief idea of what it does.> | |
634 | Copyright (C) <year> <name of author> | |
635 | ||
636 | This program is free software: you can redistribute it and/or modify | |
637 | it under the terms of the GNU General Public License as published by | |
638 | the Free Software Foundation, either version 3 of the License, or | |
639 | (at your option) any later version. | |
640 | ||
641 | This program is distributed in the hope that it will be useful, | |
642 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
643 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
644 | GNU General Public License for more details. | |
645 | ||
646 | You should have received a copy of the GNU General Public License | |
647 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |
648 | ||
649 | Also add information on how to contact you by electronic and paper mail. | |
650 | ||
651 | If the program does terminal interaction, make it output a short | |
652 | notice like this when it starts in an interactive mode: | |
653 | ||
654 | <program> Copyright (C) <year> <name of author> | |
655 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |
656 | This is free software, and you are welcome to redistribute it | |
657 | under certain conditions; type `show c' for details. | |
658 | ||
659 | The hypothetical commands `show w' and `show c' should show the appropriate | |
660 | parts of the General Public License. Of course, your program's commands | |
661 | might be different; for a GUI interface, you would use an "about box". | |
662 | ||
663 | You should also get your employer (if you work as a programmer) or school, | |
664 | if any, to sign a "copyright disclaimer" for the program, if necessary. | |
665 | For more information on this, and how to apply and follow the GNU GPL, see | |
666 | <http://www.gnu.org/licenses/>. | |
667 | ||
668 | The GNU General Public License does not permit incorporating your program | |
669 | into proprietary programs. If your program is a subroutine library, you | |
670 | may consider it more useful to permit linking proprietary applications with | |
671 | the library. If this is what you want to do, use the GNU Lesser General | |
672 | Public License instead of this License. But first, please read | |
673 | <http://www.gnu.org/philosophy/why-not-lgpl.html>. |
0 | GNU LESSER GENERAL PUBLIC LICENSE | |
1 | Version 3, 29 June 2007 | |
2 | ||
3 | Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | |
4 | Everyone is permitted to copy and distribute verbatim copies | |
5 | of this license document, but changing it is not allowed. | |
6 | ||
7 | ||
8 | This version of the GNU Lesser General Public License incorporates | |
9 | the terms and conditions of version 3 of the GNU General Public | |
10 | License, supplemented by the additional permissions listed below. | |
11 | ||
12 | 0. Additional Definitions. | |
13 | ||
14 | As used herein, "this License" refers to version 3 of the GNU Lesser | |
15 | General Public License, and the "GNU GPL" refers to version 3 of the GNU | |
16 | General Public License. | |
17 | ||
18 | "The Library" refers to a covered work governed by this License, | |
19 | other than an Application or a Combined Work as defined below. | |
20 | ||
21 | An "Application" is any work that makes use of an interface provided | |
22 | by the Library, but which is not otherwise based on the Library. | |
23 | Defining a subclass of a class defined by the Library is deemed a mode | |
24 | of using an interface provided by the Library. | |
25 | ||
26 | A "Combined Work" is a work produced by combining or linking an | |
27 | Application with the Library. The particular version of the Library | |
28 | with which the Combined Work was made is also called the "Linked | |
29 | Version". | |
30 | ||
31 | The "Minimal Corresponding Source" for a Combined Work means the | |
32 | Corresponding Source for the Combined Work, excluding any source code | |
33 | for portions of the Combined Work that, considered in isolation, are | |
34 | based on the Application, and not on the Linked Version. | |
35 | ||
36 | The "Corresponding Application Code" for a Combined Work means the | |
37 | object code and/or source code for the Application, including any data | |
38 | and utility programs needed for reproducing the Combined Work from the | |
39 | Application, but excluding the System Libraries of the Combined Work. | |
40 | ||
41 | 1. Exception to Section 3 of the GNU GPL. | |
42 | ||
43 | You may convey a covered work under sections 3 and 4 of this License | |
44 | without being bound by section 3 of the GNU GPL. | |
45 | ||
46 | 2. Conveying Modified Versions. | |
47 | ||
48 | If you modify a copy of the Library, and, in your modifications, a | |
49 | facility refers to a function or data to be supplied by an Application | |
50 | that uses the facility (other than as an argument passed when the | |
51 | facility is invoked), then you may convey a copy of the modified | |
52 | version: | |
53 | ||
54 | a) under this License, provided that you make a good faith effort to | |
55 | ensure that, in the event an Application does not supply the | |
56 | function or data, the facility still operates, and performs | |
57 | whatever part of its purpose remains meaningful, or | |
58 | ||
59 | b) under the GNU GPL, with none of the additional permissions of | |
60 | this License applicable to that copy. | |
61 | ||
62 | 3. Object Code Incorporating Material from Library Header Files. | |
63 | ||
64 | The object code form of an Application may incorporate material from | |
65 | a header file that is part of the Library. You may convey such object | |
66 | code under terms of your choice, provided that, if the incorporated | |
67 | material is not limited to numerical parameters, data structure | |
68 | layouts and accessors, or small macros, inline functions and templates | |
69 | (ten or fewer lines in length), you do both of the following: | |
70 | ||
71 | a) Give prominent notice with each copy of the object code that the | |
72 | Library is used in it and that the Library and its use are | |
73 | covered by this License. | |
74 | ||
75 | b) Accompany the object code with a copy of the GNU GPL and this license | |
76 | document. | |
77 | ||
78 | 4. Combined Works. | |
79 | ||
80 | You may convey a Combined Work under terms of your choice that, | |
81 | taken together, effectively do not restrict modification of the | |
82 | portions of the Library contained in the Combined Work and reverse | |
83 | engineering for debugging such modifications, if you also do each of | |
84 | the following: | |
85 | ||
86 | a) Give prominent notice with each copy of the Combined Work that | |
87 | the Library is used in it and that the Library and its use are | |
88 | covered by this License. | |
89 | ||
90 | b) Accompany the Combined Work with a copy of the GNU GPL and this license | |
91 | document. | |
92 | ||
93 | c) For a Combined Work that displays copyright notices during | |
94 | execution, include the copyright notice for the Library among | |
95 | these notices, as well as a reference directing the user to the | |
96 | copies of the GNU GPL and this license document. | |
97 | ||
98 | d) Do one of the following: | |
99 | ||
100 | 0) Convey the Minimal Corresponding Source under the terms of this | |
101 | License, and the Corresponding Application Code in a form | |
102 | suitable for, and under terms that permit, the user to | |
103 | recombine or relink the Application with a modified version of | |
104 | the Linked Version to produce a modified Combined Work, in the | |
105 | manner specified by section 6 of the GNU GPL for conveying | |
106 | Corresponding Source. | |
107 | ||
108 | 1) Use a suitable shared library mechanism for linking with the | |
109 | Library. A suitable mechanism is one that (a) uses at run time | |
110 | a copy of the Library already present on the user's computer | |
111 | system, and (b) will operate properly with a modified version | |
112 | of the Library that is interface-compatible with the Linked | |
113 | Version. | |
114 | ||
115 | e) Provide Installation Information, but only if you would otherwise | |
116 | be required to provide such information under section 6 of the | |
117 | GNU GPL, and only to the extent that such information is | |
118 | necessary to install and execute a modified version of the | |
119 | Combined Work produced by recombining or relinking the | |
120 | Application with a modified version of the Linked Version. (If | |
121 | you use option 4d0, the Installation Information must accompany | |
122 | the Minimal Corresponding Source and Corresponding Application | |
123 | Code. If you use option 4d1, you must provide the Installation | |
124 | Information in the manner specified by section 6 of the GNU GPL | |
125 | for conveying Corresponding Source.) | |
126 | ||
127 | 5. Combined Libraries. | |
128 | ||
129 | You may place library facilities that are a work based on the | |
130 | Library side by side in a single library together with other library | |
131 | facilities that are not Applications and are not covered by this | |
132 | License, and convey such a combined library under terms of your | |
133 | choice, if you do both of the following: | |
134 | ||
135 | a) Accompany the combined library with a copy of the same work based | |
136 | on the Library, uncombined with any other library facilities, | |
137 | conveyed under the terms of this License. | |
138 | ||
139 | b) Give prominent notice with the combined library that part of it | |
140 | is a work based on the Library, and explaining where to find the | |
141 | accompanying uncombined form of the same work. | |
142 | ||
143 | 6. Revised Versions of the GNU Lesser General Public License. | |
144 | ||
145 | The Free Software Foundation may publish revised and/or new versions | |
146 | of the GNU Lesser General Public License from time to time. Such new | |
147 | versions will be similar in spirit to the present version, but may | |
148 | differ in detail to address new problems or concerns. | |
149 | ||
150 | Each version is given a distinguishing version number. If the | |
151 | Library as you received it specifies that a certain numbered version | |
152 | of the GNU Lesser General Public License "or any later version" | |
153 | applies to it, you have the option of following the terms and | |
154 | conditions either of that published version or of any later version | |
155 | published by the Free Software Foundation. If the Library as you | |
156 | received it does not specify a version number of the GNU Lesser | |
157 | General Public License, you may choose any version of the GNU Lesser | |
158 | General Public License ever published by the Free Software Foundation. | |
159 | ||
160 | If the Library as you received it specifies that a proxy can decide | |
161 | whether future versions of the GNU Lesser General Public License shall | |
162 | apply, that proxy's public statement of acceptance of any version is | |
163 | permanent authorization for you to choose that version for the | |
164 | Library. |
0 | CC ?= gcc | |
1 | CFLAGS = -g -Wall -pedantic | |
2 | ||
3 | ENABLE_TIMER ?= no | |
4 | ||
5 | ifeq '$(ENABLE_TIMER)' 'yes' | |
6 | CFLAGS += -DCU_ENABLE_TIMER | |
7 | endif | |
8 | ||
9 | TARGETS = libcu.a | |
10 | ||
11 | TEST_OBJS = test.o test2.o | |
12 | ||
13 | all: $(TARGETS) | |
14 | ||
15 | libcu.a: cu.o | |
16 | ar cr $@ $^ | |
17 | ranlib $@ | |
18 | cu.o: cu.c cu.h | |
19 | $(CC) $(CFLAGS) -c -o $@ $< | |
20 | ||
21 | test: $(TEST_OBJS) libcu.a | |
22 | $(CC) $(CFLAGS) -o $@ $(TEST_OBJS) -L./ -lcu | |
23 | test-segfault: test-segfault.c libcu.a | |
24 | $(CC) $(CFLAGS) -o $@ $^ -L./ -lcu | |
25 | ||
26 | %.o: %.c | |
27 | $(CC) $(CFLAGS) -c -o $@ $< | |
28 | ||
29 | check: test test-segfault | |
30 | mkdir -p regressions | |
31 | touch regressions/testSuiteName{,2}.{out,err} | |
32 | touch regressions/testSuiteTest2.{out,err} | |
33 | -./test | |
34 | -cd regressions && ../check-regressions | |
35 | @echo "" | |
36 | @echo "======= SEGFAULT: =========" | |
37 | @echo "" | |
38 | -./test-segfault | |
39 | ||
40 | clean: | |
41 | rm -f *.o | |
42 | rm -f test | |
43 | rm -f test-segfault | |
44 | rm -f $(TARGETS) | |
45 | rm -f tmp.* | |
46 | rm -rf regressions | |
47 | ||
48 | .PHONY: all clean check |
0 | AM_CPPFLAGS = -DCU_ENABLE_TIMER | |
1 | ||
2 | check_LTLIBRARIES = libcu.la | |
3 | ||
4 | libcu_la_SOURCES = cu.c cu.h | |
5 |
0 | #!/usr/bin/python | |
1 | ## | |
2 | # CU - C unit testing framework | |
3 | # --------------------------------- | |
4 | # Copyright (c)2007,2008 Daniel Fiser <danfis@danfis.cz> | |
5 | # | |
6 | # | |
7 | # This file is part of CU. | |
8 | # | |
9 | # CU is free software; you can redistribute it and/or modify | |
10 | # it under the terms of the GNU Lesser General Public License as | |
11 | # published by the Free Software Foundation; either version 3 of | |
12 | # the License, or (at your option) any later version. | |
13 | # | |
14 | # CU is distributed in the hope that it will be useful, | |
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | # GNU Lesser General Public License for more details. | |
18 | # | |
19 | # You should have received a copy of the GNU Lesser General Public License | |
20 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
21 | # | |
22 | ||
23 | from subprocess import Popen, PIPE | |
24 | import os | |
25 | import re | |
26 | import sys | |
27 | import math | |
28 | from getopt import gnu_getopt, GetoptError | |
29 | ||
30 | EPS = 0.6 | |
31 | BASE_DIR = "." | |
32 | MAX_DIFF_LINES = 20 | |
33 | EXACT = False | |
34 | ||
35 | PROGRESS_ON = True | |
36 | MSG_BASE = "" | |
37 | ||
38 | class Hunk: | |
39 | """ This class represents one hunk from diff. """ | |
40 | ||
41 | def __init__(self): | |
42 | self.added = [] | |
43 | self.deleted = [] | |
44 | self.lines = [] | |
45 | ||
46 | # to identify lines with floating point numbers | |
47 | self.re_is_num = re.compile("^.*[0-9].*$") | |
48 | ||
49 | # pattern to match floating point number | |
50 | self.num_pattern = r"-?(?:(?:[0-9]+(?:\.[0-9]*)?)|(?:\.[0-9]+))(?:[eE]-?[0-9]+)?" | |
51 | self.re_num = re.compile(self.num_pattern) | |
52 | ||
53 | def numLines(self): | |
54 | return len(self.lines) | |
55 | def numLinesAdded(self): | |
56 | return len(self.added) | |
57 | def numLinesDeleted(self): | |
58 | return len(self.deleted) | |
59 | ||
60 | def addLineAdded(self, line): | |
61 | self.added.append(line) | |
62 | def addLineDeleted(self, line): | |
63 | self.deleted.append(line) | |
64 | def addLine(self, line): | |
65 | self.lines.append(line) | |
66 | ||
67 | def getLines(self): | |
68 | return self.lines | |
69 | def getLinesAdded(self): | |
70 | return self.added | |
71 | def getLinesDeleted(self): | |
72 | return self.deleted | |
73 | ||
74 | def __eq(self, num1, num2): | |
75 | """ Returns True if num1 equals to num2 with respect to EPS | |
76 | (defined above) """ | |
77 | return math.fabs(num1 - num2) < EPS | |
78 | ||
79 | def checkFloats(self): | |
80 | """ This method try to check if only difference between added and | |
81 | deleted lines of this hunk is different precission of floating | |
82 | point numbers | |
83 | """ | |
84 | ||
85 | # If number of added and deleted lines differs, then there is more | |
86 | # differences that precission of floating point numbers | |
87 | if self.numLinesAdded() != self.numLinesDeleted(): | |
88 | return False | |
89 | ||
90 | for i in xrange(0, self.numLinesAdded()): | |
91 | # if any line does not contain number - return False because | |
92 | # there must be more differences than in numbers | |
93 | if not self.re_is_num.match(self.added[i]) \ | |
94 | or not self.re_is_num.match(self.deleted[i]): | |
95 | return False | |
96 | ||
97 | line1 = self.added[i] | |
98 | line2 = self.deleted[i] | |
99 | ||
100 | # Extract all floating point numbers from each line | |
101 | nums1 = self.re_num.findall(line1) | |
102 | nums2 = self.re_num.findall(line2) | |
103 | # and remove all empty strings | |
104 | nums1 = filter(lambda x: len(x) > 0, nums1) | |
105 | nums2 = filter(lambda x: len(x) > 0, nums2) | |
106 | ||
107 | # if length of list nums1 does not equal to length of nums2 | |
108 | # return False | |
109 | if len(nums1) != len(nums2): | |
110 | return False | |
111 | ||
112 | # iterate trough all numbers | |
113 | for j in xrange(0, len(nums1)): | |
114 | # if numbers do not equal to each other return False | |
115 | if not self.__eq(float(nums1[j]), float(nums2[j])): | |
116 | return False | |
117 | ||
118 | # compare the rest of lines | |
119 | line1 = self.re_num.sub("", line1) | |
120 | line2 = self.re_num.sub("", line2) | |
121 | if line1 != line2: | |
122 | return False | |
123 | ||
124 | # If it does not fail anywhere, added and deleted lines must be | |
125 | # same | |
126 | return True | |
127 | ||
128 | ||
129 | class Diff: | |
130 | """ Represents whole diff. """ | |
131 | ||
132 | def __init__(self): | |
133 | self.hunks = [] | |
134 | self.lines = 0 | |
135 | self.omitted_lines = 0 | |
136 | ||
137 | def addHunk(self, hunk): | |
138 | self.hunks.append(hunk) | |
139 | self.lines += hunk.numLines() | |
140 | ||
141 | def numLines(self): | |
142 | return self.lines | |
143 | def numOmittedLines(self): | |
144 | return self.omitted_lines | |
145 | ||
146 | def getHunks(self): | |
147 | return self.hunks | |
148 | def numHunks(self): | |
149 | return len(self.hunks) | |
150 | ||
151 | def checkFloats(self): | |
152 | """ Will call method checkFloats on each hunk """ | |
153 | hks = self.hunks[:] | |
154 | self.hunks = [] | |
155 | self.lines = 0 | |
156 | for h in hks: | |
157 | if not h.checkFloats(): | |
158 | self.hunks.append(h) | |
159 | self.lines += h.numLines() | |
160 | else: | |
161 | self.omitted_lines += h.numLines() | |
162 | ||
163 | ||
164 | ||
165 | class Parser: | |
166 | def __init__(self, fin): | |
167 | self.fin = fin | |
168 | self.line = "" | |
169 | self.diff = Diff() | |
170 | self.cur_hunk = None | |
171 | ||
172 | # to recognize beginning of hunk: | |
173 | self.re_hunk = re.compile(r"^[0-9]*(,[0-9]*){0,1}[a-zA-Z]?[0-9]*(,[0-9]*){0,1}$") | |
174 | ||
175 | self.re_added = re.compile(r"^> (.*)$") | |
176 | self.re_deleted = re.compile(r"^< (.*)$") | |
177 | ||
178 | def __readNextLine(self): | |
179 | self.line = self.fin.readline() | |
180 | if len(self.line) == 0: | |
181 | return False | |
182 | return True | |
183 | ||
184 | def parse(self): | |
185 | global PROGRESS_ON | |
186 | global MSG_BASE | |
187 | ||
188 | num_lines = 0 | |
189 | while self.__readNextLine(): | |
190 | # beggining of hunk | |
191 | if self.re_hunk.match(self.line): | |
192 | if self.cur_hunk is not None: | |
193 | self.diff.addHunk(self.cur_hunk) | |
194 | self.cur_hunk = Hunk() | |
195 | self.cur_hunk.addLine(self.line) | |
196 | ||
197 | # line added | |
198 | match = self.re_added.match(self.line) | |
199 | if match is not None: | |
200 | self.cur_hunk.addLine(self.line) | |
201 | self.cur_hunk.addLineAdded(match.group(1)) | |
202 | ||
203 | # line deleted | |
204 | match = self.re_deleted.match(self.line) | |
205 | if match is not None: | |
206 | self.cur_hunk.addLine(self.line) | |
207 | self.cur_hunk.addLineDeleted(match.group(1)) | |
208 | ||
209 | num_lines += 1 | |
210 | ||
211 | if PROGRESS_ON and num_lines % 50 == 0: | |
212 | print MSG_BASE, "[ %08d ]" % num_lines, "\r", | |
213 | sys.stdout.flush() | |
214 | ||
215 | # last push to list of hunks | |
216 | if self.cur_hunk is not None: | |
217 | self.diff.addHunk(self.cur_hunk) | |
218 | ||
219 | if PROGRESS_ON: | |
220 | print MSG_BASE, " ", "\r", | |
221 | sys.stdout.flush() | |
222 | ||
223 | def getDiff(self): | |
224 | return self.diff | |
225 | ||
226 | ||
227 | def regressionFilesInDir(): | |
228 | """ Returns sorted list of pairs of filenames where first name in pair | |
229 | is tmp. file and second corresponding file with saved regressions. | |
230 | """ | |
231 | ||
232 | re_tmp_out_file = re.compile(r"tmp\.(.*\.out)") | |
233 | re_tmp_err_file = re.compile(r"tmp\.(.*\.err)") | |
234 | files = [] | |
235 | ||
236 | all_files = os.listdir(".") | |
237 | all_files.sort() | |
238 | for file in all_files: | |
239 | res = re_tmp_out_file.match(file) | |
240 | if res is not None: | |
241 | fname = res.group(1) | |
242 | tmp = [file, ""] | |
243 | for file2 in all_files: | |
244 | if file2 == fname: | |
245 | tmp = [file, file2,] | |
246 | break | |
247 | files.append(tmp) | |
248 | ||
249 | res = re_tmp_err_file.match(file) | |
250 | if res is not None: | |
251 | fname = res.group(1) | |
252 | tmp = [file, ""] | |
253 | for file2 in all_files: | |
254 | if file2 == fname: | |
255 | tmp = [file, file2,] | |
256 | break | |
257 | files.append(tmp) | |
258 | ||
259 | return files | |
260 | ||
261 | ||
262 | def MSG(str = "", wait = False): | |
263 | if wait: | |
264 | print str, | |
265 | else: | |
266 | print str | |
267 | def MSGOK(prestr = "", str = "", poststr = ""): | |
268 | print prestr, "\033[0;32m" + str + "\033[0;0m", poststr | |
269 | def MSGFAIL(prestr = "", str = "", poststr = ""): | |
270 | print prestr, "\033[0;31m" + str + "\033[0;0m", poststr | |
271 | def MSGINFO(prestr = "", str = "", poststr = ""): | |
272 | print prestr, "\033[0;33m" + str + "\033[0;0m", poststr | |
273 | def dumpLines(lines, prefix = "", wait = False, max_lines = -1): | |
274 | line_num = 0 | |
275 | if wait: | |
276 | for line in lines: | |
277 | print prefix, line, | |
278 | line_num += 1 | |
279 | if max_lines >= 0 and line_num > max_lines: | |
280 | break | |
281 | else: | |
282 | for line in lines: | |
283 | print prefix, line | |
284 | line_num += 1 | |
285 | if max_lines >= 0 and line_num > max_lines: | |
286 | break | |
287 | ||
288 | def main(files): | |
289 | global MSG_BASE | |
290 | ||
291 | # As first compute length of columns | |
292 | len1 = 0 | |
293 | len2 = 0 | |
294 | for filenames in files: | |
295 | if len(filenames[0]) > len1: | |
296 | len1 = len(filenames[0]) | |
297 | if len(filenames[1]) > len2: | |
298 | len2 = len(filenames[1]) | |
299 | ||
300 | for filenames in files: | |
301 | if len(filenames[1]) == 0: | |
302 | MSGFAIL("", "===", "Can't compare %s %s, bacause %s does not exist!" % \ | |
303 | (filenames[0], filenames[0][4:], filenames[0][4:])) | |
304 | continue | |
305 | ||
306 | cmd = ["diff", filenames[0], filenames[1]] | |
307 | MSG_BASE = "Comparing %s and %s" % \ | |
308 | (filenames[0].ljust(len1) ,filenames[1].ljust(len2)) | |
309 | if not PROGRESS_ON: | |
310 | print MSG_BASE, | |
311 | sys.stdout.flush() | |
312 | ||
313 | pipe = Popen(cmd, stdout=PIPE) | |
314 | parser = Parser(pipe.stdout) | |
315 | parser.parse() | |
316 | diff = parser.getDiff() | |
317 | if not EXACT: | |
318 | diff.checkFloats() | |
319 | ||
320 | if PROGRESS_ON: | |
321 | print MSG_BASE, | |
322 | ||
323 | if diff.numHunks() == 0: | |
324 | MSGOK(" [", "OK", "]") | |
325 | if diff.numOmittedLines() > 0: | |
326 | MSGINFO(" -->", str(diff.numOmittedLines()) + " lines from diff omitted") | |
327 | else: | |
328 | MSGFAIL(" [", "FAILED", "]") | |
329 | if diff.numOmittedLines() > 0: | |
330 | MSGINFO(" -->", str(diff.numOmittedLines()) + " lines from diff omitted") | |
331 | MSGINFO(" -->", "Diff has " + str(diff.numLines()) + " lines") | |
332 | ||
333 | if diff.numLines() <= MAX_DIFF_LINES: | |
334 | MSGINFO(" -->", "Diff:") | |
335 | for h in diff.getHunks(): | |
336 | dumpLines(h.getLines(), " |", True) | |
337 | else: | |
338 | MSGINFO(" -->", "Printing only first " + str(MAX_DIFF_LINES) + " lines:") | |
339 | lines = [] | |
340 | for h in diff.getHunks(): | |
341 | lines += h.getLines() | |
342 | if len(lines) > MAX_DIFF_LINES: | |
343 | break; | |
344 | dumpLines(lines, " |", True, MAX_DIFF_LINES) | |
345 | ||
346 | def usage(): | |
347 | print "Usage: " + sys.argv[0] + " [ OPTIONS ] [ directory, [ directory, [ ... ] ] ]" | |
348 | print "" | |
349 | print " OPTIONS:" | |
350 | print " --help / -h none Print this help" | |
351 | print " --exact / -e none Switch do exact comparasion of files" | |
352 | print " --not-exact / -n none Switch do non exact comparasion of files (default behaviour)" | |
353 | print " --max-diff-lines int Maximum of lines of diff which can be printed (default " + str(MAX_DIFF_LINES) + ")" | |
354 | print " --eps float Precision of floating point numbers (epsilon) (default " + str(EPS) + ")" | |
355 | print " --no-progress none Turn off progress bar" | |
356 | print " --progress none Turn on progress bar (default)" | |
357 | print "" | |
358 | print " This program is able to compare files with regressions generated by CU testsuites." | |
359 | print " You can specify directories which are to be searched for regression files." | |
360 | print " In non exact copmarasion mode (which is default), this program tries to compare" | |
361 | print " floating point numbers in files with respect to specified precision (see --eps) and" | |
362 | print " those lines which differ only in precission of floating point numbers are omitted." | |
363 | print "" | |
364 | sys.exit(-1) | |
365 | ||
366 | ||
367 | ||
368 | # Init: | |
369 | ||
370 | # Set up base dir | |
371 | BASE_DIR = os.getcwd() | |
372 | ||
373 | # Parse command line options: | |
374 | optlist, args = gnu_getopt(sys.argv[1:], | |
375 | "hen", | |
376 | ["help", "max-diff-lines=", "eps=", \ | |
377 | "exact", "not-exact", \ | |
378 | "no-progress", "progress"]) | |
379 | for opt in optlist: | |
380 | if opt[0] == "--help" or opt[0] == "-h": | |
381 | usage() | |
382 | if opt[0] == "--exact" or opt[0] == "-e": | |
383 | EXACT = True | |
384 | if opt[0] == "--not-exact" or opt[0] == "-n": | |
385 | EXACT = False | |
386 | if opt[0] == "--max-diff-lines": | |
387 | MAX_DIFF_LINES = int(opt[1]) | |
388 | if opt[0] == "--eps": | |
389 | EPS = float(opt[1]) | |
390 | if opt[0] == "--no-progress": | |
391 | PROGRESS_ON = False | |
392 | if opt[0] == "--progress": | |
393 | PROGRESS_ON = True | |
394 | ||
395 | if len(args) == 0: | |
396 | files = regressionFilesInDir() | |
397 | main(files) | |
398 | else: | |
399 | for dir in args: | |
400 | os.chdir(BASE_DIR) | |
401 | ||
402 | MSGINFO() | |
403 | MSGINFO("", "Processing directory '" + dir + "':") | |
404 | MSGINFO() | |
405 | try: | |
406 | os.chdir(dir) | |
407 | except: | |
408 | MSGFAIL(" -->", "Directory '" + dir + "' does not exist.") | |
409 | files = regressionFilesInDir() | |
410 | main(files) | |
411 | ||
412 | sys.exit(0) |
0 | /*** | |
1 | * CU - C unit testing framework | |
2 | * --------------------------------- | |
3 | * Copyright (c)2007,2008,2009 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of CU. | |
7 | * | |
8 | * CU is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU Lesser General Public License as | |
10 | * published by the Free Software Foundation; either version 3 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * CU is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public License | |
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 | */ | |
21 | ||
22 | #include <stdlib.h> | |
23 | #include <stdio.h> | |
24 | #include <string.h> | |
25 | #include <sys/wait.h> | |
26 | ||
27 | #include "cu.h" | |
28 | ||
29 | /** Declared here, because I didn't find header file where it is declared */ | |
30 | char *strsignal(int sig); | |
31 | ||
32 | const char *cu_current_test; | |
33 | const char *cu_current_test_suite; | |
34 | int cu_success_test_suites = 0; | |
35 | int cu_fail_test_suites = 0; | |
36 | int cu_success_tests = 0; | |
37 | int cu_fail_tests = 0; | |
38 | int cu_success_checks = 0; | |
39 | int cu_fail_checks = 0; | |
40 | ||
41 | char cu_out_prefix[CU_OUT_PREFIX_LENGTH+1] = ""; | |
42 | ||
43 | ||
44 | /* globally used file descriptor for reading/writing messages */ | |
45 | int fd; | |
46 | ||
47 | /* indicate if test was failed */ | |
48 | int test_failed; | |
49 | ||
50 | /* codes of messages */ | |
51 | #define CHECK_FAILED '0' | |
52 | #define CHECK_SUCCEED '1' | |
53 | #define TEST_FAILED '2' | |
54 | #define TEST_SUCCEED '3' | |
55 | #define TEST_SUITE_FAILED '4' | |
56 | #define TEST_SUITE_SUCCEED '5' | |
57 | #define END '6' | |
58 | #define TEST_NAME '7' | |
59 | ||
60 | /* predefined messages */ | |
61 | #define MSG_CHECK_SUCCEED write(fd, "1\n", 2) | |
62 | #define MSG_TEST_FAILED write(fd, "2\n", 2) | |
63 | #define MSG_TEST_SUCCEED write(fd, "3\n", 2) | |
64 | #define MSG_TEST_SUITE_FAILED write(fd, "4\n", 2) | |
65 | #define MSG_TEST_SUITE_SUCCEED write(fd, "5\n", 2) | |
66 | #define MSG_END write(fd, "6\n", 2) | |
67 | ||
68 | /* length of buffers */ | |
69 | #define BUF_LEN 1000 | |
70 | #define MSGBUF_LEN 300 | |
71 | ||
72 | ||
73 | static void redirect_out_err(const char *testName); | |
74 | static void close_out_err(void); | |
75 | static void run_test_suite(const char *ts_name, cu_test_suite_t *ts); | |
76 | static void receive_messages(void); | |
77 | ||
78 | static void cu_run_fork(const char *ts_name, cu_test_suite_t *test_suite); | |
79 | static void cu_print_results(void); | |
80 | ||
81 | void cu_run(int argc, char *argv[]) | |
82 | { | |
83 | cu_test_suites_t *tss; | |
84 | int i; | |
85 | char found = 0; | |
86 | ||
87 | if (argc > 1){ | |
88 | for (i=1; i < argc; i++){ | |
89 | tss = cu_test_suites; | |
90 | while (tss->name != NULL && tss->test_suite != NULL){ | |
91 | if (strcmp(argv[i], tss->name) == 0){ | |
92 | found = 1; | |
93 | cu_run_fork(tss->name, tss->test_suite); | |
94 | break; | |
95 | } | |
96 | tss++; | |
97 | } | |
98 | ||
99 | if (tss->name == NULL || tss->test_suite == NULL){ | |
100 | fprintf(stderr, "ERROR: Could not find test suite '%s'\n", argv[i]); | |
101 | } | |
102 | } | |
103 | ||
104 | if (found == 1) | |
105 | cu_print_results(); | |
106 | ||
107 | }else{ | |
108 | tss = cu_test_suites; | |
109 | while (tss->name != NULL && tss->test_suite != NULL){ | |
110 | cu_run_fork(tss->name, tss->test_suite); | |
111 | tss++; | |
112 | } | |
113 | cu_print_results(); | |
114 | } | |
115 | ||
116 | ||
117 | } | |
118 | ||
119 | static void cu_run_fork(const char *ts_name, cu_test_suite_t *ts) | |
120 | { | |
121 | int pipefd[2]; | |
122 | int pid; | |
123 | int status; | |
124 | ||
125 | if (pipe(pipefd) == -1){ | |
126 | perror("Pipe error"); | |
127 | exit(-1); | |
128 | } | |
129 | ||
130 | fprintf(stdout, " -> %s [IN PROGESS]\n", ts_name); | |
131 | fflush(stdout); | |
132 | ||
133 | pid = fork(); | |
134 | if (pid < 0){ | |
135 | perror("Fork error"); | |
136 | exit(-1); | |
137 | } | |
138 | ||
139 | if (pid == 0){ | |
140 | /* close read end of pipe */ | |
141 | close(pipefd[0]); | |
142 | ||
143 | fd = pipefd[1]; | |
144 | ||
145 | /* run testsuite, messages go to fd */ | |
146 | run_test_suite(ts_name, ts); | |
147 | ||
148 | MSG_END; | |
149 | close(fd); | |
150 | ||
151 | /* stop process where running testsuite */ | |
152 | exit(0); | |
153 | }else{ | |
154 | /* close write end of pipe */ | |
155 | close(pipefd[1]); | |
156 | ||
157 | fd = pipefd[0]; | |
158 | ||
159 | /* receive and interpret all messages */ | |
160 | receive_messages(); | |
161 | ||
162 | /* wait for children */ | |
163 | wait(&status); | |
164 | if (!WIFEXITED(status)){ /* if child process ends up abnormaly */ | |
165 | if (WIFSIGNALED(status)){ | |
166 | fprintf(stdout, "Test suite was terminated by signal %d (%s).\n", | |
167 | WTERMSIG(status), strsignal(WTERMSIG(status))); | |
168 | }else{ | |
169 | fprintf(stdout, "Test suite terminated abnormaly!\n"); | |
170 | } | |
171 | ||
172 | /* mark this test suite as failed, because was terminated | |
173 | * prematurely */ | |
174 | cu_fail_test_suites++; | |
175 | } | |
176 | ||
177 | close(fd); | |
178 | ||
179 | fprintf(stdout, " -> %s [DONE]\n\n", ts_name); | |
180 | fflush(stdout); | |
181 | } | |
182 | ||
183 | } | |
184 | ||
185 | static void run_test_suite(const char *ts_name, cu_test_suite_t *ts) | |
186 | { | |
187 | int test_suite_failed = 0; | |
188 | char buffer[MSGBUF_LEN]; | |
189 | int len; | |
190 | ||
191 | /* set up current test suite name for later messaging... */ | |
192 | cu_current_test_suite = ts_name; | |
193 | ||
194 | /* redirect stdout and stderr */ | |
195 | redirect_out_err(cu_current_test_suite); | |
196 | ||
197 | while (ts->name != NULL && ts->func != NULL){ | |
198 | test_failed = 0; | |
199 | ||
200 | /* set up name of test for later messaging */ | |
201 | cu_current_test = ts->name; | |
202 | ||
203 | /* send message what test is currently running */ | |
204 | len = snprintf(buffer, MSGBUF_LEN, "%c --> Running %s...\n", | |
205 | TEST_NAME, cu_current_test); | |
206 | write(fd, buffer, len); | |
207 | ||
208 | /* run test */ | |
209 | (*(ts->func))(); | |
210 | ||
211 | if (test_failed){ | |
212 | MSG_TEST_FAILED; | |
213 | test_suite_failed = 1; | |
214 | }else{ | |
215 | MSG_TEST_SUCCEED; | |
216 | } | |
217 | ||
218 | ts++; /* next test in test suite */ | |
219 | } | |
220 | ||
221 | if (test_suite_failed){ | |
222 | MSG_TEST_SUITE_FAILED; | |
223 | }else{ | |
224 | MSG_TEST_SUITE_SUCCEED; | |
225 | } | |
226 | ||
227 | /* close redirected stdout and stderr */ | |
228 | close_out_err(); | |
229 | } | |
230 | ||
231 | ||
232 | static void receive_messages(void) | |
233 | { | |
234 | char buf[BUF_LEN]; /* buffer */ | |
235 | int buf_len; /* how many chars stored in buf */ | |
236 | char bufout[MSGBUF_LEN]; /* buffer which can be printed out */ | |
237 | int bufout_len; | |
238 | int state = 0; /* 0 - waiting for code, 1 - copy msg to stdout */ | |
239 | int i; | |
240 | int end = 0; /* end of messages? */ | |
241 | ||
242 | bufout_len = 0; | |
243 | while((buf_len = read(fd, buf, BUF_LEN)) > 0 && !end){ | |
244 | for (i=0; i < buf_len; i++){ | |
245 | ||
246 | /* Prepare message for printing out */ | |
247 | if (state == 1 || state == 2){ | |
248 | if (bufout_len < MSGBUF_LEN) | |
249 | bufout[bufout_len++] = buf[i]; | |
250 | } | |
251 | ||
252 | /* reset state on '\n' in msg */ | |
253 | if (buf[i] == '\n'){ | |
254 | /* copy messages out */ | |
255 | if (state == 1) | |
256 | write(1, bufout, bufout_len); | |
257 | if (state == 2) | |
258 | write(2, bufout, bufout_len); | |
259 | ||
260 | state = 0; | |
261 | bufout_len = 0; | |
262 | continue; | |
263 | } | |
264 | ||
265 | if (state == 0){ | |
266 | if (buf[i] == CHECK_FAILED){ | |
267 | cu_fail_checks++; | |
268 | state = 2; | |
269 | }else if (buf[i] == TEST_NAME){ | |
270 | state = 1; | |
271 | }else if (buf[i] == CHECK_SUCCEED){ | |
272 | cu_success_checks++; | |
273 | }else if (buf[i] == TEST_FAILED){ | |
274 | cu_fail_tests++; | |
275 | }else if (buf[i] == TEST_SUCCEED){ | |
276 | cu_success_tests++; | |
277 | }else if (buf[i] == TEST_SUITE_FAILED){ | |
278 | cu_fail_test_suites++; | |
279 | }else if (buf[i] == TEST_SUITE_SUCCEED){ | |
280 | cu_success_test_suites++; | |
281 | }else if (buf[i] == END){ | |
282 | end = 1; | |
283 | break; | |
284 | } | |
285 | } | |
286 | } | |
287 | } | |
288 | } | |
289 | ||
290 | void cu_success_assertation(void) | |
291 | { | |
292 | MSG_CHECK_SUCCEED; | |
293 | } | |
294 | ||
295 | void cu_fail_assertation(const char *file, int line, const char *msg) | |
296 | { | |
297 | char buf[MSGBUF_LEN]; | |
298 | int len; | |
299 | ||
300 | len = snprintf(buf, MSGBUF_LEN, "%c%s:%d (%s::%s) :: %s\n", | |
301 | CHECK_FAILED, | |
302 | file, line, cu_current_test_suite, cu_current_test, msg); | |
303 | write(fd, buf, len); | |
304 | ||
305 | /* enable test_failed flag */ | |
306 | test_failed = 1; | |
307 | } | |
308 | ||
309 | static void cu_print_results(void) | |
310 | { | |
311 | fprintf(stdout, "\n"); | |
312 | fprintf(stdout, "==================================================\n"); | |
313 | fprintf(stdout, "| | failed | succeed | total |\n"); | |
314 | fprintf(stdout, "|------------------------------------------------|\n"); | |
315 | fprintf(stdout, "| assertations: | %6d | %7d | %5d |\n", | |
316 | cu_fail_checks, cu_success_checks, | |
317 | cu_success_checks+cu_fail_checks); | |
318 | fprintf(stdout, "| tests: | %6d | %7d | %5d |\n", | |
319 | cu_fail_tests, cu_success_tests, | |
320 | cu_success_tests+cu_fail_tests); | |
321 | fprintf(stdout, "| tests suites: | %6d | %7d | %5d |\n", | |
322 | cu_fail_test_suites, cu_success_test_suites, | |
323 | cu_success_test_suites+cu_fail_test_suites); | |
324 | fprintf(stdout, "==================================================\n"); | |
325 | } | |
326 | ||
327 | void cu_set_out_prefix(const char *str) | |
328 | { | |
329 | strncpy(cu_out_prefix, str, CU_OUT_PREFIX_LENGTH); | |
330 | } | |
331 | ||
332 | static void redirect_out_err(const char *test_name) | |
333 | { | |
334 | char buf[100]; | |
335 | ||
336 | snprintf(buf, 99, "%stmp.%s.out", cu_out_prefix, test_name); | |
337 | if (freopen(buf, "w", stdout) == NULL){ | |
338 | perror("Redirecting of stdout failed"); | |
339 | exit(-1); | |
340 | } | |
341 | ||
342 | snprintf(buf, 99, "%stmp.%s.err", cu_out_prefix, test_name); | |
343 | if (freopen(buf, "w", stderr) == NULL){ | |
344 | perror("Redirecting of stderr failed"); | |
345 | exit(-1); | |
346 | } | |
347 | } | |
348 | ||
349 | static void close_out_err(void) | |
350 | { | |
351 | fclose(stdout); | |
352 | fclose(stderr); | |
353 | } | |
354 | ||
355 | ||
356 | #ifdef CU_ENABLE_TIMER | |
357 | /* global variables for timer functions */ | |
358 | struct timespec __cu_timer; | |
359 | static struct timespec __cu_timer_start, __cu_timer_stop; | |
360 | ||
361 | const struct timespec *cuTimer(void) | |
362 | { | |
363 | return &__cu_timer; | |
364 | } | |
365 | ||
366 | void cuTimerStart(void) | |
367 | { | |
368 | clock_gettime(CLOCK_MONOTONIC, &__cu_timer_start); | |
369 | } | |
370 | ||
371 | const struct timespec *cuTimerStop(void) | |
372 | { | |
373 | clock_gettime(CLOCK_MONOTONIC, &__cu_timer_stop); | |
374 | ||
375 | /* store into t difference between time_start and time_end */ | |
376 | if (__cu_timer_stop.tv_nsec > __cu_timer_start.tv_nsec){ | |
377 | __cu_timer.tv_nsec = __cu_timer_stop.tv_nsec - __cu_timer_start.tv_nsec; | |
378 | __cu_timer.tv_sec = __cu_timer_stop.tv_sec - __cu_timer_start.tv_sec; | |
379 | }else{ | |
380 | __cu_timer.tv_nsec = __cu_timer_stop.tv_nsec + 1000000000L - __cu_timer_start.tv_nsec; | |
381 | __cu_timer.tv_sec = __cu_timer_stop.tv_sec - 1 - __cu_timer_start.tv_sec; | |
382 | } | |
383 | ||
384 | return &__cu_timer; | |
385 | } | |
386 | #endif /* CU_ENABLE_TIMER */ |
0 | /*** | |
1 | * CU - C unit testing framework | |
2 | * --------------------------------- | |
3 | * Copyright (c)2007,2008,2009 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of CU. | |
7 | * | |
8 | * CU is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU Lesser General Public License as | |
10 | * published by the Free Software Foundation; either version 3 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * CU is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public License | |
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 | */ | |
21 | ||
22 | #ifndef _CU_H_ | |
23 | #define _CU_H_ | |
24 | ||
25 | #ifdef CU_ENABLE_TIMER | |
26 | # include <time.h> | |
27 | #endif /* CU_ENABLE_TIMER */ | |
28 | ||
29 | #ifdef __cplusplus | |
30 | extern "C" { | |
31 | #endif /* __cplusplus */ | |
32 | ||
33 | /***** PUBLIC API *****/ | |
34 | /** | |
35 | * Define test | |
36 | */ | |
37 | #define TEST(name) \ | |
38 | void name(void) | |
39 | ||
40 | /** | |
41 | * Define testsuite | |
42 | */ | |
43 | #define TEST_SUITE(name) \ | |
44 | cu_test_suite_t test_suite_##name[] = | |
45 | /** | |
46 | * Must be on the end of list of tests. | |
47 | */ | |
48 | #define TEST_SUITE_CLOSURE \ | |
49 | { NULL, NULL } | |
50 | ||
51 | #define TEST_SUITES \ | |
52 | cu_test_suites_t cu_test_suites[] = | |
53 | #define TEST_SUITES_CLOSURE \ | |
54 | { NULL, NULL } | |
55 | #define TEST_SUITE_ADD(name) \ | |
56 | { #name, test_suite_##name } | |
57 | ||
58 | /** | |
59 | * Add test to testsuite | |
60 | */ | |
61 | #define TEST_ADD(name) \ | |
62 | { #name, name } | |
63 | ||
64 | #define CU_RUN(argc, argv) \ | |
65 | cu_run(argc, argv) | |
66 | ||
67 | /** | |
68 | * Set prefix for files printed out. Must contain trailing /. | |
69 | */ | |
70 | #define CU_SET_OUT_PREFIX(str) \ | |
71 | cu_set_out_prefix(str) | |
72 | ||
73 | /** | |
74 | * Assertations | |
75 | * Assertations with suffix 'M' (e.g. assertTrueM) is variation of macro | |
76 | * where is possible to specify error message. | |
77 | */ | |
78 | #define assertTrueM(a, message) \ | |
79 | if (a){ \ | |
80 | cu_success_assertation(); \ | |
81 | }else{ \ | |
82 | cu_fail_assertation(__FILE__, __LINE__, message); \ | |
83 | } | |
84 | #define assertTrue(a) \ | |
85 | assertTrueM((a), #a " is not true") | |
86 | ||
87 | #define assertFalseM(a, message) \ | |
88 | assertTrueM(!(a), message) | |
89 | #define assertFalse(a) \ | |
90 | assertFalseM((a), #a " is not false") | |
91 | ||
92 | #define assertEqualsM(a,b,message) \ | |
93 | assertTrueM((a) == (b), message) | |
94 | #define assertEquals(a,b) \ | |
95 | assertEqualsM((a), (b), #a " not equals " #b) | |
96 | ||
97 | #define assertNotEqualsM(a,b,message) \ | |
98 | assertTrueM((a) != (b), message) | |
99 | #define assertNotEquals(a,b) \ | |
100 | assertNotEqualsM((a), (b), #a " equals " #b) | |
101 | /***** PUBLIC API END *****/ | |
102 | ||
103 | ||
104 | #include <unistd.h> | |
105 | ||
106 | #define CU_MAX_NAME_LENGTH 30 | |
107 | ||
108 | typedef void (*cu_test_func_t)(void); | |
109 | typedef struct _cu_test_suite_t { | |
110 | const char *name; | |
111 | cu_test_func_t func; | |
112 | } cu_test_suite_t; | |
113 | typedef struct _cu_test_suites_t { | |
114 | const char *name; | |
115 | cu_test_suite_t *test_suite; | |
116 | } cu_test_suites_t; | |
117 | ||
118 | extern cu_test_suites_t cu_test_suites[]; | |
119 | ||
120 | extern const char *cu_current_test; | |
121 | extern const char *cu_current_test_suite; | |
122 | ||
123 | extern int cu_success_test_suites; | |
124 | extern int cu_fail_test_suites; | |
125 | extern int cu_success_tests; | |
126 | extern int cu_fail_tests; | |
127 | extern int cu_success_checks; | |
128 | extern int cu_fail_checks; | |
129 | ||
130 | #define CU_OUT_PREFIX_LENGTH 30 | |
131 | extern char cu_out_prefix[CU_OUT_PREFIX_LENGTH+1]; | |
132 | ||
133 | void cu_run(int argc, char *argv[]); | |
134 | void cu_success_assertation(void); | |
135 | void cu_fail_assertation(const char *file, int line, const char *msg); | |
136 | void cu_set_out_prefix(const char *str); | |
137 | ||
138 | /** Timer **/ | |
139 | #ifdef CU_ENABLE_TIMER | |
140 | extern struct timespec __cu_timer; | |
141 | ||
142 | /** | |
143 | * Returns value of timer. (as timespec struct) | |
144 | */ | |
145 | const struct timespec *cuTimer(void); | |
146 | ||
147 | /** | |
148 | * Starts timer. | |
149 | */ | |
150 | void cuTimerStart(void); | |
151 | ||
152 | /** | |
153 | * Stops timer and record elapsed time from last call of cuTimerStart(). | |
154 | * Returns current value of timer. | |
155 | */ | |
156 | const struct timespec *cuTimerStop(void); | |
157 | #endif /* CU_ENABLE_TIMER */ | |
158 | ||
159 | #ifdef __cplusplus | |
160 | } | |
161 | #endif /* __cplusplus */ | |
162 | ||
163 | #endif |
0 | #!/bin/bash | |
1 | ||
2 | repo=http://git.danfis.cz/cu.git | |
3 | files="COPYING \ | |
4 | COPYING.LESSER \ | |
5 | cu.h \ | |
6 | cu.c \ | |
7 | Makefile \ | |
8 | check-regressions \ | |
9 | .gitignore \ | |
10 | " | |
11 | rm -rf cu | |
12 | git clone $repo | |
13 | for file in $files; do | |
14 | mv cu/"$file" . | |
15 | done; | |
16 | rm -rf cu |
0 | #include <stdio.h> | |
1 | #include <cu/cu.h> | |
2 | #include <ccd/ccd.h> | |
3 | #include "support.h" | |
4 | #include "common.h" | |
5 | ||
6 | ||
7 | TEST(cylcylSetUp) | |
8 | { | |
9 | } | |
10 | ||
11 | TEST(cylcylTearDown) | |
12 | { | |
13 | } | |
14 | ||
15 | ||
16 | TEST(cylcylAlignedX) | |
17 | { | |
18 | ccd_t ccd; | |
19 | CCD_CYL(c1); | |
20 | CCD_CYL(c2); | |
21 | size_t i; | |
22 | int res; | |
23 | ||
24 | CCD_INIT(&ccd); | |
25 | ccd.support1 = ccdSupport; | |
26 | ccd.support2 = ccdSupport; | |
27 | ||
28 | c1.radius = 0.35; | |
29 | c1.height = 0.5; | |
30 | c2.radius = 0.5; | |
31 | c2.height = 1.; | |
32 | ||
33 | ccdVec3Set(&c1.pos, -5., 0., 0.); | |
34 | for (i = 0; i < 100; i++){ | |
35 | res = ccdGJKIntersect(&c1, &c2, &ccd); | |
36 | ||
37 | if (i < 42 || i > 58){ | |
38 | assertFalse(res); | |
39 | }else{ | |
40 | assertTrue(res); | |
41 | } | |
42 | ||
43 | c1.pos.v[0] += 0.1; | |
44 | } | |
45 | } | |
46 | ||
47 | TEST(cylcylAlignedY) | |
48 | { | |
49 | ccd_t ccd; | |
50 | CCD_CYL(c1); | |
51 | CCD_CYL(c2); | |
52 | size_t i; | |
53 | int res; | |
54 | ||
55 | CCD_INIT(&ccd); | |
56 | ccd.support1 = ccdSupport; | |
57 | ccd.support2 = ccdSupport; | |
58 | ||
59 | c1.radius = 0.35; | |
60 | c1.height = 0.5; | |
61 | c2.radius = 0.5; | |
62 | c2.height = 1.; | |
63 | ||
64 | ccdVec3Set(&c1.pos, 0., -5., 0.); | |
65 | for (i = 0; i < 100; i++){ | |
66 | res = ccdGJKIntersect(&c1, &c2, &ccd); | |
67 | ||
68 | if (i < 42 || i > 58){ | |
69 | assertFalse(res); | |
70 | }else{ | |
71 | assertTrue(res); | |
72 | } | |
73 | ||
74 | c1.pos.v[1] += 0.1; | |
75 | } | |
76 | } | |
77 | ||
78 | TEST(cylcylAlignedZ) | |
79 | { | |
80 | ccd_t ccd; | |
81 | CCD_CYL(c1); | |
82 | CCD_CYL(c2); | |
83 | size_t i; | |
84 | int res; | |
85 | ||
86 | CCD_INIT(&ccd); | |
87 | ccd.support1 = ccdSupport; | |
88 | ccd.support2 = ccdSupport; | |
89 | ||
90 | c1.radius = 0.35; | |
91 | c1.height = 0.5; | |
92 | c2.radius = 0.5; | |
93 | c2.height = 1.; | |
94 | ||
95 | ccdVec3Set(&c1.pos, 0., 0., -5.); | |
96 | for (i = 0; i < 100; i++){ | |
97 | res = ccdGJKIntersect(&c1, &c2, &ccd); | |
98 | ||
99 | if (i < 43 || i > 57){ | |
100 | assertFalse(res); | |
101 | }else{ | |
102 | assertTrue(res); | |
103 | } | |
104 | ||
105 | c1.pos.v[2] += 0.1; | |
106 | } | |
107 | } | |
108 | ||
109 | #define TOSVT() \ | |
110 | svtObjPen(&cyl1, &cyl2, stdout, "Pen 1", depth, &dir, &pos); \ | |
111 | ccdVec3Scale(&dir, depth); \ | |
112 | ccdVec3Add(&cyl2.pos, &dir); \ | |
113 | svtObjPen(&cyl1, &cyl2, stdout, "Pen 1", depth, &dir, &pos) | |
114 | ||
115 | TEST(cylcylPenetrationEPA) | |
116 | { | |
117 | ccd_t ccd; | |
118 | CCD_CYL(cyl1); | |
119 | CCD_CYL(cyl2); | |
120 | int res; | |
121 | ccd_vec3_t axis; | |
122 | ccd_real_t depth; | |
123 | ccd_vec3_t dir, pos; | |
124 | ||
125 | fprintf(stderr, "\n\n\n---- cylcylPenetration ----\n\n\n"); | |
126 | ||
127 | cyl1.radius = 0.35; | |
128 | cyl1.height = 0.5; | |
129 | cyl2.radius = 0.5; | |
130 | cyl2.height = 1.; | |
131 | ||
132 | CCD_INIT(&ccd); | |
133 | ccd.support1 = ccdSupport; | |
134 | ccd.support2 = ccdSupport; | |
135 | ||
136 | ccdVec3Set(&cyl2.pos, 0., 0., 0.3); | |
137 | res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
138 | assertTrue(res == 0); | |
139 | recPen(depth, &dir, &pos, stdout, "Pen 1"); | |
140 | //TOSVT(); | |
141 | ||
142 | ccdVec3Set(&cyl1.pos, 0.3, 0.1, 0.1); | |
143 | res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
144 | assertTrue(res == 0); | |
145 | recPen(depth, &dir, &pos, stdout, "Pen 2"); | |
146 | //TOSVT(); <<< | |
147 | ||
148 | ccdVec3Set(&axis, 0., 1., 1.); | |
149 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
150 | ccdVec3Set(&cyl2.pos, 0., 0., 0.); | |
151 | res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
152 | assertTrue(res == 0); | |
153 | recPen(depth, &dir, &pos, stdout, "Pen 3"); | |
154 | //TOSVT(); | |
155 | ||
156 | ccdVec3Set(&axis, 0., 1., 1.); | |
157 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
158 | ccdVec3Set(&cyl2.pos, -0.2, 0.7, 0.2); | |
159 | res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
160 | assertTrue(res == 0); | |
161 | recPen(depth, &dir, &pos, stdout, "Pen 4"); | |
162 | //TOSVT(); | |
163 | ||
164 | ccdVec3Set(&axis, 0.567, 1.2, 1.); | |
165 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
166 | ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); | |
167 | res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
168 | assertTrue(res == 0); | |
169 | recPen(depth, &dir, &pos, stdout, "Pen 5"); | |
170 | //TOSVT(); | |
171 | ||
172 | ccdVec3Set(&axis, -4.567, 1.2, 0.); | |
173 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 3., &axis); | |
174 | ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); | |
175 | res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
176 | assertTrue(res == 0); | |
177 | recPen(depth, &dir, &pos, stdout, "Pen 6"); | |
178 | //TOSVT(); | |
179 | } |
0 | #ifndef CYL_CYL | |
1 | #define CYL_CYL | |
2 | ||
3 | #include <cu/cu.h> | |
4 | ||
5 | TEST(cylcylSetUp); | |
6 | TEST(cylcylTearDown); | |
7 | ||
8 | TEST(cylcylAlignedX); | |
9 | TEST(cylcylAlignedY); | |
10 | TEST(cylcylAlignedZ); | |
11 | ||
12 | TEST(cylcylPenetrationEPA); | |
13 | ||
14 | TEST_SUITE(TSCylCyl) { | |
15 | TEST_ADD(cylcylSetUp), | |
16 | ||
17 | TEST_ADD(cylcylAlignedX), | |
18 | TEST_ADD(cylcylAlignedY), | |
19 | TEST_ADD(cylcylAlignedZ), | |
20 | ||
21 | TEST_ADD(cylcylPenetrationEPA), | |
22 | ||
23 | TEST_ADD(cylcylTearDown), | |
24 | TEST_SUITE_CLOSURE | |
25 | }; | |
26 | ||
27 | #endif | |
28 |
0 | #include "vec3.h" | |
1 | #include "polytope.h" | |
2 | #include "boxbox.h" | |
3 | #include "spheresphere.h" | |
4 | #include "cylcyl.h" | |
5 | #include "boxcyl.h" | |
6 | ||
7 | #include "mpr_boxbox.h" | |
8 | #include "mpr_cylcyl.h" | |
9 | #include "mpr_boxcyl.h" | |
10 | ||
11 | TEST_SUITES { | |
12 | TEST_SUITE_ADD(TSVec3), | |
13 | TEST_SUITE_ADD(TSPt), | |
14 | TEST_SUITE_ADD(TSBoxBox), | |
15 | TEST_SUITE_ADD(TSSphereSphere), | |
16 | TEST_SUITE_ADD(TSCylCyl), | |
17 | TEST_SUITE_ADD(TSBoxCyl), | |
18 | ||
19 | TEST_SUITE_ADD(TSMPRBoxBox), | |
20 | TEST_SUITE_ADD(TSMPRCylCyl), | |
21 | TEST_SUITE_ADD(TSMPRBoxCyl), | |
22 | ||
23 | TEST_SUITES_CLOSURE | |
24 | }; | |
25 | int main(int argc, char *argv[]) | |
26 | { | |
27 | CU_SET_OUT_PREFIX("regressions/"); | |
28 | CU_RUN(argc, argv); | |
29 | ||
30 | return 0; | |
31 | } |
0 | #include <stdio.h> | |
1 | #include <cu/cu.h> | |
2 | ||
3 | #include <ccd/ccd.h> | |
4 | #include "support.h" | |
5 | #include <ccd/vec3.h> | |
6 | #include <ccd/dbg.h> | |
7 | #include "common.h" | |
8 | ||
9 | ||
10 | TEST(mprBoxboxAlignedX) | |
11 | { | |
12 | size_t i; | |
13 | ccd_t ccd; | |
14 | CCD_BOX(box1); | |
15 | CCD_BOX(box2); | |
16 | int res; | |
17 | ||
18 | CCD_INIT(&ccd); | |
19 | ccd.support1 = ccdSupport; | |
20 | ccd.support2 = ccdSupport; | |
21 | ccd.center1 = ccdObjCenter; | |
22 | ccd.center2 = ccdObjCenter; | |
23 | ||
24 | box1.x = 1; | |
25 | box1.y = 2; | |
26 | box1.z = 1; | |
27 | box2.x = 2; | |
28 | box2.y = 1; | |
29 | box2.z = 2; | |
30 | ||
31 | ccdVec3Set(&box1.pos, -5., 0., 0.); | |
32 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
33 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
34 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
35 | for (i = 0; i < 100; i++){ | |
36 | res = ccdMPRIntersect(&box1, &box2, &ccd); | |
37 | if (i < 35 || i > 65){ | |
38 | assertFalse(res); | |
39 | }else if (i != 35 && i != 65){ | |
40 | assertTrue(res); | |
41 | } | |
42 | ||
43 | box1.pos.v[0] += 0.1; | |
44 | } | |
45 | ||
46 | box1.x = 0.1; | |
47 | box1.y = 0.2; | |
48 | box1.z = 0.1; | |
49 | box2.x = 0.2; | |
50 | box2.y = 0.1; | |
51 | box2.z = 0.2; | |
52 | ||
53 | ccdVec3Set(&box1.pos, -0.5, 0., 0.); | |
54 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
55 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
56 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
57 | for (i = 0; i < 100; i++){ | |
58 | res = ccdMPRIntersect(&box1, &box2, &ccd); | |
59 | ||
60 | if (i < 35 || i > 65){ | |
61 | assertFalse(res); | |
62 | }else if (i != 35 && i != 65){ | |
63 | assertTrue(res); | |
64 | } | |
65 | ||
66 | box1.pos.v[0] += 0.01; | |
67 | } | |
68 | ||
69 | ||
70 | box1.x = 1; | |
71 | box1.y = 2; | |
72 | box1.z = 1; | |
73 | box2.x = 2; | |
74 | box2.y = 1; | |
75 | box2.z = 2; | |
76 | ||
77 | ccdVec3Set(&box1.pos, -5., -0.1, 0.); | |
78 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
79 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
80 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
81 | for (i = 0; i < 100; i++){ | |
82 | res = ccdMPRIntersect(&box1, &box2, &ccd); | |
83 | ||
84 | if (i < 35 || i > 65){ | |
85 | assertFalse(res); | |
86 | }else if (i != 35 && i != 65){ | |
87 | assertTrue(res); | |
88 | } | |
89 | ||
90 | box1.pos.v[0] += 0.1; | |
91 | } | |
92 | } | |
93 | ||
94 | TEST(mprBoxboxAlignedY) | |
95 | { | |
96 | size_t i; | |
97 | ccd_t ccd; | |
98 | CCD_BOX(box1); | |
99 | CCD_BOX(box2); | |
100 | int res; | |
101 | ||
102 | CCD_INIT(&ccd); | |
103 | ccd.support1 = ccdSupport; | |
104 | ccd.support2 = ccdSupport; | |
105 | ccd.center1 = ccdObjCenter; | |
106 | ccd.center2 = ccdObjCenter; | |
107 | ||
108 | box1.x = 1; | |
109 | box1.y = 2; | |
110 | box1.z = 1; | |
111 | box2.x = 2; | |
112 | box2.y = 1; | |
113 | box2.z = 2; | |
114 | ||
115 | ccdVec3Set(&box1.pos, 0., -5., 0.); | |
116 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
117 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
118 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
119 | for (i = 0; i < 100; i++){ | |
120 | res = ccdMPRIntersect(&box1, &box2, &ccd); | |
121 | ||
122 | if (i < 35 || i > 65){ | |
123 | assertFalse(res); | |
124 | }else if (i != 35 && i != 65){ | |
125 | assertTrue(res); | |
126 | } | |
127 | ||
128 | box1.pos.v[1] += 0.1; | |
129 | } | |
130 | } | |
131 | ||
132 | TEST(mprBoxboxAlignedZ) | |
133 | { | |
134 | size_t i; | |
135 | ccd_t ccd; | |
136 | CCD_BOX(box1); | |
137 | CCD_BOX(box2); | |
138 | int res; | |
139 | ||
140 | CCD_INIT(&ccd); | |
141 | ccd.support1 = ccdSupport; | |
142 | ccd.support2 = ccdSupport; | |
143 | ccd.center1 = ccdObjCenter; | |
144 | ccd.center2 = ccdObjCenter; | |
145 | ||
146 | box1.x = 1; | |
147 | box1.y = 2; | |
148 | box1.z = 1; | |
149 | box2.x = 2; | |
150 | box2.y = 1; | |
151 | box2.z = 2; | |
152 | ||
153 | ccdVec3Set(&box1.pos, 0., 0., -5.); | |
154 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
155 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
156 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
157 | for (i = 0; i < 100; i++){ | |
158 | res = ccdMPRIntersect(&box1, &box2, &ccd); | |
159 | ||
160 | if (i < 35 || i > 65){ | |
161 | assertFalse(res); | |
162 | }else if (i != 35 && i != 65){ | |
163 | assertTrue(res); | |
164 | } | |
165 | ||
166 | box1.pos.v[2] += 0.1; | |
167 | } | |
168 | } | |
169 | ||
170 | ||
171 | TEST(mprBoxboxRot) | |
172 | { | |
173 | size_t i; | |
174 | ccd_t ccd; | |
175 | CCD_BOX(box1); | |
176 | CCD_BOX(box2); | |
177 | int res; | |
178 | ccd_vec3_t axis; | |
179 | ccd_real_t angle; | |
180 | ||
181 | CCD_INIT(&ccd); | |
182 | ccd.support1 = ccdSupport; | |
183 | ccd.support2 = ccdSupport; | |
184 | ccd.center1 = ccdObjCenter; | |
185 | ccd.center2 = ccdObjCenter; | |
186 | ||
187 | box1.x = 1; | |
188 | box1.y = 2; | |
189 | box1.z = 1; | |
190 | box2.x = 2; | |
191 | box2.y = 1; | |
192 | box2.z = 2; | |
193 | ||
194 | ccdVec3Set(&box1.pos, -5., 0.5, 0.); | |
195 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
196 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
197 | ccdVec3Set(&axis, 0., 1., 0.); | |
198 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
199 | ||
200 | for (i = 0; i < 100; i++){ | |
201 | res = ccdMPRIntersect(&box1, &box2, &ccd); | |
202 | ||
203 | if (i < 33 || i > 67){ | |
204 | assertFalse(res); | |
205 | }else if (i != 33 && i != 67){ | |
206 | assertTrue(res); | |
207 | } | |
208 | ||
209 | box1.pos.v[0] += 0.1; | |
210 | } | |
211 | ||
212 | box1.x = 1; | |
213 | box1.y = 1; | |
214 | box1.z = 1; | |
215 | box2.x = 1; | |
216 | box2.y = 1; | |
217 | box2.z = 1; | |
218 | ||
219 | ccdVec3Set(&box1.pos, -1.01, 0., 0.); | |
220 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
221 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
222 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
223 | ||
224 | ccdVec3Set(&axis, 0., 1., 0.); | |
225 | angle = 0.; | |
226 | for (i = 0; i < 30; i++){ | |
227 | res = ccdMPRIntersect(&box1, &box2, &ccd); | |
228 | ||
229 | if (i != 0 && i != 10 && i != 20){ | |
230 | assertTrue(res); | |
231 | }else{ | |
232 | assertFalse(res); | |
233 | } | |
234 | ||
235 | angle += M_PI / 20.; | |
236 | ccdQuatSetAngleAxis(&box1.quat, angle, &axis); | |
237 | } | |
238 | ||
239 | } | |
240 | ||
241 | ||
242 | ||
243 | static void pConf(ccd_box_t *box1, ccd_box_t *box2, const ccd_vec3_t *v) | |
244 | { | |
245 | fprintf(stdout, "# box1.pos: [%lf %lf %lf]\n", | |
246 | ccdVec3X(&box1->pos), ccdVec3Y(&box1->pos), ccdVec3Z(&box1->pos)); | |
247 | fprintf(stdout, "# box1->quat: [%lf %lf %lf %lf]\n", | |
248 | box1->quat.q[0], box1->quat.q[1], box1->quat.q[2], box1->quat.q[3]); | |
249 | fprintf(stdout, "# box2->pos: [%lf %lf %lf]\n", | |
250 | ccdVec3X(&box2->pos), ccdVec3Y(&box2->pos), ccdVec3Z(&box2->pos)); | |
251 | fprintf(stdout, "# box2->quat: [%lf %lf %lf %lf]\n", | |
252 | box2->quat.q[0], box2->quat.q[1], box2->quat.q[2], box2->quat.q[3]); | |
253 | fprintf(stdout, "# sep: [%lf %lf %lf]\n", | |
254 | ccdVec3X(v), ccdVec3Y(v), ccdVec3Z(v)); | |
255 | fprintf(stdout, "#\n"); | |
256 | } | |
257 | ||
258 | TEST(mprBoxboxSeparate) | |
259 | { | |
260 | ccd_t ccd; | |
261 | CCD_BOX(box1); | |
262 | CCD_BOX(box2); | |
263 | int res; | |
264 | ccd_vec3_t sep, expsep, expsep2, axis; | |
265 | ||
266 | fprintf(stderr, "\n\n\n---- boxboxSeparate ----\n\n\n"); | |
267 | ||
268 | box1.x = box1.y = box1.z = 1.; | |
269 | box2.x = 0.5; | |
270 | box2.y = 1.; | |
271 | box2.z = 1.5; | |
272 | ||
273 | ||
274 | CCD_INIT(&ccd); | |
275 | ccd.support1 = ccdSupport; | |
276 | ccd.support2 = ccdSupport; | |
277 | ccd.center1 = ccdObjCenter; | |
278 | ccd.center2 = ccdObjCenter; | |
279 | ||
280 | ccdVec3Set(&box1.pos, -0.5, 0.5, 0.2); | |
281 | res = ccdMPRIntersect(&box1, &box2, &ccd); | |
282 | assertTrue(res); | |
283 | ||
284 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
285 | assertTrue(res == 0); | |
286 | ccdVec3Set(&expsep, 0.25, 0., 0.); | |
287 | assertTrue(ccdVec3Eq(&sep, &expsep)); | |
288 | ||
289 | ccdVec3Scale(&sep, -1.); | |
290 | ccdVec3Add(&box1.pos, &sep); | |
291 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
292 | assertTrue(res == 0); | |
293 | ccdVec3Set(&expsep, 0., 0., 0.); | |
294 | assertTrue(ccdVec3Eq(&sep, &expsep)); | |
295 | ||
296 | ||
297 | ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); | |
298 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
299 | assertTrue(res == 0); | |
300 | ccdVec3Set(&expsep, 0., 0., -0.25); | |
301 | assertTrue(ccdVec3Eq(&sep, &expsep)); | |
302 | ||
303 | ||
304 | ||
305 | box1.x = box1.y = box1.z = 1.; | |
306 | box2.x = box2.y = box2.z = 1.; | |
307 | ccdVec3Set(&axis, 0., 0., 1.); | |
308 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
309 | ccdVec3Set(&box1.pos, 0., 0., 0.); | |
310 | ||
311 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
312 | assertTrue(res == 0); | |
313 | ccdVec3Set(&expsep, 0., 0., 1.); | |
314 | ccdVec3Set(&expsep2, 0., 0., -1.); | |
315 | assertTrue(ccdVec3Eq(&sep, &expsep) || ccdVec3Eq(&sep, &expsep2)); | |
316 | ||
317 | ||
318 | ||
319 | box1.x = box1.y = box1.z = 1.; | |
320 | ccdVec3Set(&axis, 0., 0., 1.); | |
321 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
322 | ccdVec3Set(&box1.pos, -0.5, 0., 0.); | |
323 | ||
324 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
325 | assertTrue(res == 0); | |
326 | pConf(&box1, &box2, &sep); | |
327 | ||
328 | ||
329 | ||
330 | box1.x = box1.y = box1.z = 1.; | |
331 | ccdVec3Set(&axis, 0., 1., 1.); | |
332 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
333 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
334 | ||
335 | res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); | |
336 | assertTrue(res == 0); | |
337 | pConf(&box1, &box2, &sep); | |
338 | } | |
339 | ||
340 | ||
341 | #define TOSVT() \ | |
342 | svtObjPen(&box1, &box2, stdout, "Pen 1", depth, &dir, &pos); \ | |
343 | ccdVec3Scale(&dir, depth); \ | |
344 | ccdVec3Add(&box2.pos, &dir); \ | |
345 | svtObjPen(&box1, &box2, stdout, "Pen 1", depth, &dir, &pos) | |
346 | ||
347 | TEST(mprBoxboxPenetration) | |
348 | { | |
349 | ccd_t ccd; | |
350 | CCD_BOX(box1); | |
351 | CCD_BOX(box2); | |
352 | int res; | |
353 | ccd_vec3_t axis; | |
354 | ccd_quat_t rot; | |
355 | ccd_real_t depth; | |
356 | ccd_vec3_t dir, pos; | |
357 | ||
358 | fprintf(stderr, "\n\n\n---- boxboxPenetration ----\n\n\n"); | |
359 | ||
360 | box1.x = box1.y = box1.z = 1.; | |
361 | box2.x = 0.5; | |
362 | box2.y = 1.; | |
363 | box2.z = 1.5; | |
364 | ||
365 | ||
366 | CCD_INIT(&ccd); | |
367 | ccd.support1 = ccdSupport; | |
368 | ccd.support2 = ccdSupport; | |
369 | ccd.center1 = ccdObjCenter; | |
370 | ccd.center2 = ccdObjCenter; | |
371 | ||
372 | /* | |
373 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
374 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
375 | assertTrue(res == 0); | |
376 | recPen(depth, &dir, &pos, stdout, "Pen 1"); | |
377 | TOSVT(); | |
378 | */ | |
379 | ||
380 | ccdVec3Set(&box2.pos, 0.1, 0., 0.); | |
381 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
382 | assertTrue(res == 0); | |
383 | recPen(depth, &dir, &pos, stdout, "Pen 1"); | |
384 | //TOSVT(); | |
385 | ||
386 | ||
387 | ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); | |
388 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
389 | assertTrue(res == 0); | |
390 | recPen(depth, &dir, &pos, stdout, "Pen 2"); | |
391 | //TOSVT(); | |
392 | ||
393 | ||
394 | box1.x = box1.y = box1.z = 1.; | |
395 | box2.x = box2.y = box2.z = 1.; | |
396 | ccdVec3Set(&axis, 0., 0., 1.); | |
397 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
398 | ccdVec3Set(&box1.pos, 0.1, 0., 0.1); | |
399 | ||
400 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
401 | assertTrue(res == 0); | |
402 | recPen(depth, &dir, &pos, stdout, "Pen 3"); | |
403 | //TOSVT(); | |
404 | ||
405 | ||
406 | box1.x = box1.y = box1.z = 1.; | |
407 | box2.x = box2.y = box2.z = 1.; | |
408 | ccdVec3Set(&axis, 0., 0., 1.); | |
409 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
410 | ccdVec3Set(&box1.pos, -0.5, 0., 0.); | |
411 | ||
412 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
413 | assertTrue(res == 0); | |
414 | recPen(depth, &dir, &pos, stdout, "Pen 4"); | |
415 | //TOSVT(); | |
416 | ||
417 | ||
418 | box1.x = box1.y = box1.z = 1.; | |
419 | box2.x = box2.y = box2.z = 1.; | |
420 | ccdVec3Set(&axis, 0., 0., 1.); | |
421 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
422 | ccdVec3Set(&box1.pos, -0.5, 0.5, 0.); | |
423 | ||
424 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
425 | assertTrue(res == 0); | |
426 | recPen(depth, &dir, &pos, stdout, "Pen 5"); | |
427 | //TOSVT(); | |
428 | ||
429 | ||
430 | box1.x = box1.y = box1.z = 1.; | |
431 | box2.x = box2.y = box2.z = 1.; | |
432 | ccdVec3Set(&box2.pos, 0.1, 0., 0.); | |
433 | ||
434 | box1.x = box1.y = box1.z = 1.; | |
435 | ccdVec3Set(&axis, 0., 1., 1.); | |
436 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
437 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
438 | ||
439 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
440 | assertTrue(res == 0); | |
441 | recPen(depth, &dir, &pos, stdout, "Pen 6"); | |
442 | //TOSVT(); | |
443 | ||
444 | ||
445 | box1.x = box1.y = box1.z = 1.; | |
446 | ccdVec3Set(&axis, 0., 1., 1.); | |
447 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
448 | ccdVec3Set(&axis, 1., 1., 1.); | |
449 | ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); | |
450 | ccdQuatMul(&box1.quat, &rot); | |
451 | ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); | |
452 | ||
453 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
454 | assertTrue(res == 0); | |
455 | recPen(depth, &dir, &pos, stdout, "Pen 7"); | |
456 | //TOSVT(); | |
457 | ||
458 | ||
459 | box1.x = box1.y = box1.z = 1.; | |
460 | box2.x = 0.2; box2.y = 0.5; box2.z = 1.; | |
461 | box2.x = box2.y = box2.z = 1.; | |
462 | ||
463 | ccdVec3Set(&axis, 0., 0., 1.); | |
464 | ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); | |
465 | ccdVec3Set(&axis, 1., 0., 0.); | |
466 | ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); | |
467 | ccdQuatMul(&box1.quat, &rot); | |
468 | ccdVec3Set(&box1.pos, -1.3, 0., 0.); | |
469 | ||
470 | ccdVec3Set(&box2.pos, 0., 0., 0.); | |
471 | ||
472 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
473 | assertTrue(res == 0); | |
474 | recPen(depth, &dir, &pos, stdout, "Pen 8"); | |
475 | //TOSVT(); | |
476 | ||
477 | ||
478 | box1.x = box1.y = box1.z = 1.; | |
479 | box2.x = 0.5; box2.y = 0.5; box2.z = .5; | |
480 | ccdVec3Set(&box1.pos, 0., 0., 0.); | |
481 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
482 | ccdVec3Set(&box2.pos, 0., 0.73, 0.); | |
483 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
484 | ||
485 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
486 | assertTrue(res == 0); | |
487 | recPen(depth, &dir, &pos, stdout, "Pen 9"); | |
488 | //TOSVT(); | |
489 | ||
490 | box1.x = box1.y = box1.z = 1.; | |
491 | box2.x = 0.5; box2.y = 0.5; box2.z = .5; | |
492 | ccdVec3Set(&box1.pos, 0., 0., 0.); | |
493 | ccdQuatSet(&box1.quat, 0., 0., 0., 1.); | |
494 | ccdVec3Set(&box2.pos, 0.3, 0.738, 0.); | |
495 | ccdQuatSet(&box2.quat, 0., 0., 0., 1.); | |
496 | ||
497 | res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); | |
498 | assertTrue(res == 0); | |
499 | recPen(depth, &dir, &pos, stdout, "Pen 10"); | |
500 | //TOSVT(); | |
501 | } |
0 | #ifndef MPR_BOX_BOX | |
1 | #define MPR_BOX_BOX | |
2 | ||
3 | #include <cu/cu.h> | |
4 | ||
5 | TEST(mprBoxboxAlignedX); | |
6 | TEST(mprBoxboxAlignedY); | |
7 | TEST(mprBoxboxAlignedZ); | |
8 | ||
9 | TEST(mprBoxboxRot); | |
10 | ||
11 | TEST(mprBoxboxSeparate); | |
12 | TEST(mprBoxboxPenetration); | |
13 | ||
14 | TEST_SUITE(TSMPRBoxBox) { | |
15 | TEST_ADD(mprBoxboxAlignedX), | |
16 | TEST_ADD(mprBoxboxAlignedY), | |
17 | TEST_ADD(mprBoxboxAlignedZ), | |
18 | TEST_ADD(mprBoxboxRot), | |
19 | TEST_ADD(mprBoxboxSeparate), | |
20 | TEST_ADD(mprBoxboxPenetration), | |
21 | ||
22 | TEST_SUITE_CLOSURE | |
23 | }; | |
24 | ||
25 | #endif |
0 | #include <cu/cu.h> | |
1 | #include "common.h" | |
2 | #include <ccd/ccd.h> | |
3 | #include "support.h" | |
4 | ||
5 | #define TOSVT() \ | |
6 | svtObjPen(&box, &cyl, stdout, "Pen 1", depth, &dir, &pos); \ | |
7 | ccdVec3Scale(&dir, depth); \ | |
8 | ccdVec3Add(&cyl.pos, &dir); \ | |
9 | svtObjPen(&box, &cyl, stdout, "Pen 1", depth, &dir, &pos) | |
10 | ||
11 | TEST(mprBoxcylIntersect) | |
12 | { | |
13 | ccd_t ccd; | |
14 | CCD_BOX(box); | |
15 | CCD_CYL(cyl); | |
16 | int res; | |
17 | ccd_vec3_t axis; | |
18 | ||
19 | box.x = 0.5; | |
20 | box.y = 1.; | |
21 | box.z = 1.5; | |
22 | cyl.radius = 0.4; | |
23 | cyl.height = 0.7; | |
24 | ||
25 | CCD_INIT(&ccd); | |
26 | ccd.support1 = ccdSupport; | |
27 | ccd.support2 = ccdSupport; | |
28 | ccd.center1 = ccdObjCenter; | |
29 | ccd.center2 = ccdObjCenter; | |
30 | ||
31 | ccdVec3Set(&cyl.pos, 0.1, 0., 0.); | |
32 | res = ccdMPRIntersect(&box, &cyl, &ccd); | |
33 | assertTrue(res); | |
34 | ||
35 | ccdVec3Set(&cyl.pos, .6, 0., 0.); | |
36 | res = ccdMPRIntersect(&box, &cyl, &ccd); | |
37 | assertTrue(res); | |
38 | ||
39 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.); | |
40 | res = ccdMPRIntersect(&box, &cyl, &ccd); | |
41 | assertTrue(res); | |
42 | ||
43 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
44 | res = ccdMPRIntersect(&box, &cyl, &ccd); | |
45 | assertTrue(res); | |
46 | ||
47 | ccdVec3Set(&axis, 0., 1., 0.); | |
48 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); | |
49 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
50 | res = ccdMPRIntersect(&box, &cyl, &ccd); | |
51 | assertTrue(res); | |
52 | ||
53 | ccdVec3Set(&axis, 0.67, 1.1, 0.12); | |
54 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); | |
55 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
56 | res = ccdMPRIntersect(&box, &cyl, &ccd); | |
57 | assertTrue(res); | |
58 | ||
59 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
60 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
61 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
62 | ccdVec3Set(&axis, 1., 1., 0.); | |
63 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
64 | ccdVec3Set(&box.pos, .6, 0., 0.5); | |
65 | res = ccdMPRIntersect(&box, &cyl, &ccd); | |
66 | assertTrue(res); | |
67 | ||
68 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
69 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
70 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
71 | ccdVec3Set(&axis, 1., 1., 0.); | |
72 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
73 | ccdVec3Set(&box.pos, .9, 0.8, 0.5); | |
74 | res = ccdMPRIntersect(&box, &cyl, &ccd); | |
75 | assertTrue(res); | |
76 | } | |
77 | ||
78 | ||
79 | ||
80 | TEST(mprBoxcylPen) | |
81 | { | |
82 | ccd_t ccd; | |
83 | CCD_BOX(box); | |
84 | CCD_CYL(cyl); | |
85 | int res; | |
86 | ccd_vec3_t axis; | |
87 | ccd_real_t depth; | |
88 | ccd_vec3_t dir, pos; | |
89 | ||
90 | box.x = 0.5; | |
91 | box.y = 1.; | |
92 | box.z = 1.5; | |
93 | cyl.radius = 0.4; | |
94 | cyl.height = 0.7; | |
95 | ||
96 | CCD_INIT(&ccd); | |
97 | ccd.support1 = ccdSupport; | |
98 | ccd.support2 = ccdSupport; | |
99 | ccd.center1 = ccdObjCenter; | |
100 | ccd.center2 = ccdObjCenter; | |
101 | ||
102 | ccdVec3Set(&cyl.pos, 0.1, 0., 0.); | |
103 | res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
104 | assertTrue(res == 0); | |
105 | recPen(depth, &dir, &pos, stdout, "Pen 1"); | |
106 | //TOSVT(); | |
107 | ||
108 | ccdVec3Set(&cyl.pos, .6, 0., 0.); | |
109 | res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
110 | assertTrue(res == 0); | |
111 | recPen(depth, &dir, &pos, stdout, "Pen 2"); | |
112 | //TOSVT(); | |
113 | ||
114 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.); | |
115 | res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
116 | assertTrue(res == 0); | |
117 | recPen(depth, &dir, &pos, stdout, "Pen 3"); | |
118 | //TOSVT(); | |
119 | ||
120 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
121 | res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
122 | assertTrue(res == 0); | |
123 | recPen(depth, &dir, &pos, stdout, "Pen 4"); | |
124 | //TOSVT(); | |
125 | ||
126 | ccdVec3Set(&axis, 0., 1., 0.); | |
127 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); | |
128 | ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); | |
129 | res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
130 | assertTrue(res == 0); | |
131 | recPen(depth, &dir, &pos, stdout, "Pen 5"); | |
132 | //TOSVT(); | |
133 | ||
134 | ccdVec3Set(&axis, 0.67, 1.1, 0.12); | |
135 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); | |
136 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
137 | res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
138 | assertTrue(res == 0); | |
139 | recPen(depth, &dir, &pos, stdout, "Pen 6"); | |
140 | //TOSVT(); | |
141 | ||
142 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
143 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
144 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
145 | ccdVec3Set(&axis, 1., 1., 0.); | |
146 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
147 | ccdVec3Set(&box.pos, .6, 0., 0.5); | |
148 | res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
149 | assertTrue(res == 0); | |
150 | recPen(depth, &dir, &pos, stdout, "Pen 7"); | |
151 | //TOSVT(); | |
152 | ||
153 | ccdVec3Set(&axis, -0.1, 2.2, -1.); | |
154 | ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); | |
155 | ccdVec3Set(&cyl.pos, .6, 0., 0.5); | |
156 | ccdVec3Set(&axis, 1., 1., 0.); | |
157 | ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); | |
158 | ccdVec3Set(&box.pos, .9, 0.8, 0.5); | |
159 | res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); | |
160 | assertTrue(res == 0); | |
161 | recPen(depth, &dir, &pos, stdout, "Pen 8"); | |
162 | //TOSVT(); | |
163 | } | |
164 |
0 | #ifndef MPR_TEST_BOXCYL_H | |
1 | #define MPR_TEST_BOXCYL_H | |
2 | ||
3 | #include <cu/cu.h> | |
4 | ||
5 | TEST(mprBoxcylIntersect); | |
6 | TEST(mprBoxcylPen); | |
7 | ||
8 | TEST_SUITE(TSMPRBoxCyl){ | |
9 | TEST_ADD(mprBoxcylIntersect), | |
10 | TEST_ADD(mprBoxcylPen), | |
11 | ||
12 | TEST_SUITE_CLOSURE | |
13 | }; | |
14 | ||
15 | #endif |
0 | #include <stdio.h> | |
1 | #include <cu/cu.h> | |
2 | #include <ccd/ccd.h> | |
3 | #include "support.h" | |
4 | #include "common.h" | |
5 | ||
6 | ||
7 | TEST(mprCylcylAlignedX) | |
8 | { | |
9 | ccd_t ccd; | |
10 | CCD_CYL(c1); | |
11 | CCD_CYL(c2); | |
12 | size_t i; | |
13 | int res; | |
14 | ||
15 | CCD_INIT(&ccd); | |
16 | ccd.support1 = ccdSupport; | |
17 | ccd.support2 = ccdSupport; | |
18 | ccd.center1 = ccdObjCenter; | |
19 | ccd.center2 = ccdObjCenter; | |
20 | ||
21 | c1.radius = 0.35; | |
22 | c1.height = 0.5; | |
23 | c2.radius = 0.5; | |
24 | c2.height = 1.; | |
25 | ||
26 | ccdVec3Set(&c1.pos, -5., 0., 0.); | |
27 | for (i = 0; i < 100; i++){ | |
28 | res = ccdMPRIntersect(&c1, &c2, &ccd); | |
29 | ||
30 | if (i < 42 || i > 58){ | |
31 | assertFalse(res); | |
32 | }else{ | |
33 | assertTrue(res); | |
34 | } | |
35 | ||
36 | c1.pos.v[0] += 0.1; | |
37 | } | |
38 | } | |
39 | ||
40 | TEST(mprCylcylAlignedY) | |
41 | { | |
42 | ccd_t ccd; | |
43 | CCD_CYL(c1); | |
44 | CCD_CYL(c2); | |
45 | size_t i; | |
46 | int res; | |
47 | ||
48 | CCD_INIT(&ccd); | |
49 | ccd.support1 = ccdSupport; | |
50 | ccd.support2 = ccdSupport; | |
51 | ccd.center1 = ccdObjCenter; | |
52 | ccd.center2 = ccdObjCenter; | |
53 | ||
54 | c1.radius = 0.35; | |
55 | c1.height = 0.5; | |
56 | c2.radius = 0.5; | |
57 | c2.height = 1.; | |
58 | ||
59 | ccdVec3Set(&c1.pos, 0., -5., 0.); | |
60 | for (i = 0; i < 100; i++){ | |
61 | res = ccdMPRIntersect(&c1, &c2, &ccd); | |
62 | ||
63 | if (i < 42 || i > 58){ | |
64 | assertFalse(res); | |
65 | }else{ | |
66 | assertTrue(res); | |
67 | } | |
68 | ||
69 | c1.pos.v[1] += 0.1; | |
70 | } | |
71 | } | |
72 | ||
73 | TEST(mprCylcylAlignedZ) | |
74 | { | |
75 | ccd_t ccd; | |
76 | CCD_CYL(c1); | |
77 | CCD_CYL(c2); | |
78 | size_t i; | |
79 | int res; | |
80 | ||
81 | CCD_INIT(&ccd); | |
82 | ccd.support1 = ccdSupport; | |
83 | ccd.support2 = ccdSupport; | |
84 | ccd.center1 = ccdObjCenter; | |
85 | ccd.center2 = ccdObjCenter; | |
86 | ||
87 | c1.radius = 0.35; | |
88 | c1.height = 0.5; | |
89 | c2.radius = 0.5; | |
90 | c2.height = 1.; | |
91 | ||
92 | ccdVec3Set(&c1.pos, 0., 0., -5.); | |
93 | for (i = 0; i < 100; i++){ | |
94 | res = ccdMPRIntersect(&c1, &c2, &ccd); | |
95 | ||
96 | if (i < 43 || i > 57){ | |
97 | assertFalse(res); | |
98 | }else{ | |
99 | assertTrue(res); | |
100 | } | |
101 | ||
102 | c1.pos.v[2] += 0.1; | |
103 | } | |
104 | } | |
105 | ||
106 | #define TOSVT() \ | |
107 | svtObjPen(&cyl1, &cyl2, stdout, "Pen 1", depth, &dir, &pos); \ | |
108 | ccdVec3Scale(&dir, depth); \ | |
109 | ccdVec3Add(&cyl2.pos, &dir); \ | |
110 | svtObjPen(&cyl1, &cyl2, stdout, "Pen 1", depth, &dir, &pos) | |
111 | ||
112 | TEST(mprCylcylPenetration) | |
113 | { | |
114 | ccd_t ccd; | |
115 | CCD_CYL(cyl1); | |
116 | CCD_CYL(cyl2); | |
117 | int res; | |
118 | ccd_vec3_t axis; | |
119 | ccd_real_t depth; | |
120 | ccd_vec3_t dir, pos; | |
121 | ||
122 | fprintf(stderr, "\n\n\n---- mprCylcylPenetration ----\n\n\n"); | |
123 | ||
124 | cyl1.radius = 0.35; | |
125 | cyl1.height = 0.5; | |
126 | cyl2.radius = 0.5; | |
127 | cyl2.height = 1.; | |
128 | ||
129 | CCD_INIT(&ccd); | |
130 | ccd.support1 = ccdSupport; | |
131 | ccd.support2 = ccdSupport; | |
132 | ccd.center1 = ccdObjCenter; | |
133 | ccd.center2 = ccdObjCenter; | |
134 | ||
135 | ccdVec3Set(&cyl2.pos, 0., 0., 0.3); | |
136 | res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
137 | assertTrue(res == 0); | |
138 | recPen(depth, &dir, &pos, stdout, "Pen 1"); | |
139 | //TOSVT(); | |
140 | ||
141 | ccdVec3Set(&cyl1.pos, 0.3, 0.1, 0.1); | |
142 | res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
143 | assertTrue(res == 0); | |
144 | recPen(depth, &dir, &pos, stdout, "Pen 2"); | |
145 | //TOSVT(); | |
146 | ||
147 | ccdVec3Set(&axis, 0., 1., 1.); | |
148 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
149 | ccdVec3Set(&cyl2.pos, 0., 0., 0.); | |
150 | res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
151 | assertTrue(res == 0); | |
152 | recPen(depth, &dir, &pos, stdout, "Pen 3"); | |
153 | //TOSVT(); | |
154 | ||
155 | ccdVec3Set(&axis, 0., 1., 1.); | |
156 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
157 | ccdVec3Set(&cyl2.pos, -0.2, 0.7, 0.2); | |
158 | res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
159 | assertTrue(res == 0); | |
160 | recPen(depth, &dir, &pos, stdout, "Pen 4"); | |
161 | //TOSVT(); | |
162 | ||
163 | ccdVec3Set(&axis, 0.567, 1.2, 1.); | |
164 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); | |
165 | ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); | |
166 | res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
167 | assertTrue(res == 0); | |
168 | recPen(depth, &dir, &pos, stdout, "Pen 5"); | |
169 | //TOSVT(); | |
170 | ||
171 | ccdVec3Set(&axis, -4.567, 1.2, 0.); | |
172 | ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 3., &axis); | |
173 | ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); | |
174 | res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); | |
175 | assertTrue(res == 0); | |
176 | recPen(depth, &dir, &pos, stdout, "Pen 6"); | |
177 | //TOSVT(); | |
178 | } |
0 | #ifndef MPR_CYL_CYL | |
1 | #define MPR_CYL_CYL | |
2 | ||
3 | #include <cu/cu.h> | |
4 | ||
5 | TEST(mprCylcylAlignedX); | |
6 | TEST(mprCylcylAlignedY); | |
7 | TEST(mprCylcylAlignedZ); | |
8 | ||
9 | TEST(mprCylcylPenetration); | |
10 | ||
11 | TEST_SUITE(TSMPRCylCyl) { | |
12 | TEST_ADD(mprCylcylAlignedX), | |
13 | TEST_ADD(mprCylcylAlignedY), | |
14 | TEST_ADD(mprCylcylAlignedZ), | |
15 | ||
16 | TEST_ADD(mprCylcylPenetration), | |
17 | ||
18 | TEST_SUITE_CLOSURE | |
19 | }; | |
20 | ||
21 | #endif | |
22 |
0 | //#undef NDEBUG | |
1 | #include <cu/cu.h> | |
2 | #include <ccd/polytope.h> | |
3 | #include <ccd/dbg.h> | |
4 | ||
5 | TEST(ptSetUp) | |
6 | { | |
7 | } | |
8 | ||
9 | TEST(ptTearDown) | |
10 | { | |
11 | } | |
12 | ||
13 | ||
14 | TEST(ptCreate1) | |
15 | { | |
16 | ccd_pt_t pt; | |
17 | ccd_pt_vertex_t *v[3]; | |
18 | ccd_pt_edge_t *e[3]; | |
19 | ccd_pt_face_t *f; | |
20 | ccd_vec3_t u; | |
21 | int res, i; | |
22 | ||
23 | DBG2("------"); | |
24 | ||
25 | ccdPtInit(&pt); | |
26 | ccdPtDestroy(&pt); | |
27 | ||
28 | ||
29 | ccdPtInit(&pt); | |
30 | ||
31 | ccdVec3Set(&u, -1., -1., 0.); | |
32 | v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); | |
33 | assertTrue(ccdVec3Eq(&u, &v[0]->v.v)); | |
34 | ||
35 | ccdVec3Set(&u, 1., 0., 0.); | |
36 | v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); | |
37 | assertTrue(ccdVec3Eq(&u, &v[1]->v.v)); | |
38 | ||
39 | ccdVec3Set(&u, 0., 0., 1.); | |
40 | v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); | |
41 | assertTrue(ccdVec3Eq(&u, &v[2]->v.v)); | |
42 | ||
43 | for (i = 0; i < 3; i++){ | |
44 | assertTrue(ccdEq(v[i]->dist, ccdVec3Len2(&v[i]->v.v))); | |
45 | } | |
46 | ||
47 | ||
48 | e[0] = ccdPtAddEdge(&pt, v[0], v[1]); | |
49 | e[1] = ccdPtAddEdge(&pt, v[1], v[2]); | |
50 | e[2] = ccdPtAddEdge(&pt, v[2], v[0]); | |
51 | for (i = 0; i < 3; i++){ | |
52 | DBG("e[%d]->dist: %lf", i, e[i]->dist); | |
53 | DBG_VEC3(&e[i]->witness, " ->witness: "); | |
54 | } | |
55 | ||
56 | f = ccdPtAddFace(&pt, e[0], e[1], e[2]); | |
57 | DBG("f->dist: %lf", f->dist); | |
58 | DBG_VEC3(&f->witness, " ->witness: "); | |
59 | ||
60 | for (i = 0; i < 3; i++){ | |
61 | res = ccdPtDelVertex(&pt, v[i]); | |
62 | assertFalse(res == 0); | |
63 | res = ccdPtDelEdge(&pt, e[i]); | |
64 | assertFalse(res == 0); | |
65 | } | |
66 | ||
67 | ccdPtDelFace(&pt, f); | |
68 | for (i = 0; i < 3; i++){ | |
69 | res = ccdPtDelVertex(&pt, v[i]); | |
70 | assertFalse(res == 0); | |
71 | } | |
72 | for (i = 0; i < 3; i++){ | |
73 | res = ccdPtDelEdge(&pt, e[i]); | |
74 | assertTrue(res == 0); | |
75 | } | |
76 | for (i = 0; i < 3; i++){ | |
77 | res = ccdPtDelVertex(&pt, v[i]); | |
78 | assertTrue(res == 0); | |
79 | } | |
80 | ||
81 | v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); | |
82 | v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); | |
83 | v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); | |
84 | ||
85 | e[0] = ccdPtAddEdge(&pt, v[0], v[1]); | |
86 | e[1] = ccdPtAddEdge(&pt, v[1], v[2]); | |
87 | e[2] = ccdPtAddEdge(&pt, v[2], v[0]); | |
88 | ||
89 | f = ccdPtAddFace(&pt, e[0], e[1], e[2]); | |
90 | ||
91 | ccdPtDestroy(&pt); | |
92 | } | |
93 | ||
94 | TEST(ptCreate2) | |
95 | { | |
96 | ccd_pt_t pt; | |
97 | ccd_pt_vertex_t *v[4]; | |
98 | ccd_pt_edge_t *e[6]; | |
99 | ccd_pt_face_t *f[4]; | |
100 | ccd_vec3_t u; | |
101 | int res, i; | |
102 | ||
103 | DBG2("------"); | |
104 | ||
105 | ccdPtInit(&pt); | |
106 | ||
107 | ccdVec3Set(&u, -1., -1., 0.); | |
108 | v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); | |
109 | assertTrue(ccdVec3Eq(&u, &v[0]->v.v)); | |
110 | ||
111 | ccdVec3Set(&u, 1., 0., 0.); | |
112 | v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); | |
113 | assertTrue(ccdVec3Eq(&u, &v[1]->v.v)); | |
114 | ||
115 | ccdVec3Set(&u, 0., 0., 1.); | |
116 | v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); | |
117 | assertTrue(ccdVec3Eq(&u, &v[2]->v.v)); | |
118 | ||
119 | ccdVec3Set(&u, 0., 1., 0.); | |
120 | v[3] = ccdPtAddVertexCoords(&pt, 0., 1., 0.); | |
121 | assertTrue(ccdVec3Eq(&u, &v[3]->v.v)); | |
122 | ||
123 | for (i = 0; i < 4; i++){ | |
124 | assertTrue(ccdEq(v[i]->dist, ccdVec3Len2(&v[i]->v.v))); | |
125 | } | |
126 | for (i = 0; i < 4; i++){ | |
127 | DBG("v[%d]->dist: %lf", i, v[i]->dist); | |
128 | DBG_VEC3(&v[i]->witness, " ->witness: "); | |
129 | } | |
130 | ||
131 | e[0] = ccdPtAddEdge(&pt, v[0], v[1]); | |
132 | e[1] = ccdPtAddEdge(&pt, v[1], v[2]); | |
133 | e[2] = ccdPtAddEdge(&pt, v[2], v[0]); | |
134 | e[3] = ccdPtAddEdge(&pt, v[3], v[0]); | |
135 | e[4] = ccdPtAddEdge(&pt, v[3], v[1]); | |
136 | e[5] = ccdPtAddEdge(&pt, v[3], v[2]); | |
137 | for (i = 0; i < 6; i++){ | |
138 | DBG("e[%d]->dist: %lf", i, e[i]->dist); | |
139 | DBG_VEC3(&e[i]->witness, " ->witness: "); | |
140 | } | |
141 | ||
142 | f[0] = ccdPtAddFace(&pt, e[0], e[1], e[2]); | |
143 | f[1] = ccdPtAddFace(&pt, e[3], e[4], e[0]); | |
144 | f[2] = ccdPtAddFace(&pt, e[4], e[5], e[1]); | |
145 | f[3] = ccdPtAddFace(&pt, e[5], e[3], e[2]); | |
146 | for (i = 0; i < 4; i++){ | |
147 | DBG("f[%d]->dist: %lf", i, f[i]->dist); | |
148 | DBG_VEC3(&f[i]->witness, " ->witness: "); | |
149 | } | |
150 | ||
151 | for (i = 0; i < 4; i++){ | |
152 | res = ccdPtDelVertex(&pt, v[i]); | |
153 | assertFalse(res == 0); | |
154 | } | |
155 | for (i = 0; i < 6; i++){ | |
156 | res = ccdPtDelEdge(&pt, e[i]); | |
157 | assertFalse(res == 0); | |
158 | } | |
159 | ||
160 | res = ccdPtDelFace(&pt, f[0]); | |
161 | for (i = 0; i < 6; i++){ | |
162 | res = ccdPtDelEdge(&pt, e[i]); | |
163 | assertFalse(res == 0); | |
164 | } | |
165 | ||
166 | res = ccdPtDelFace(&pt, f[1]); | |
167 | assertTrue(ccdPtDelEdge(&pt, e[0]) == 0); | |
168 | assertFalse(ccdPtDelEdge(&pt, e[1]) == 0); | |
169 | assertFalse(ccdPtDelEdge(&pt, e[2]) == 0); | |
170 | assertFalse(ccdPtDelEdge(&pt, e[3]) == 0); | |
171 | assertFalse(ccdPtDelEdge(&pt, e[4]) == 0); | |
172 | assertFalse(ccdPtDelEdge(&pt, e[5]) == 0); | |
173 | for (i = 0; i < 4; i++){ | |
174 | res = ccdPtDelVertex(&pt, v[i]); | |
175 | assertFalse(res == 0); | |
176 | } | |
177 | ||
178 | res = ccdPtDelFace(&pt, f[2]); | |
179 | assertTrue(ccdPtDelEdge(&pt, e[1]) == 0); | |
180 | assertTrue(ccdPtDelEdge(&pt, e[4]) == 0); | |
181 | assertFalse(ccdPtDelEdge(&pt, e[2]) == 0); | |
182 | assertFalse(ccdPtDelEdge(&pt, e[3]) == 0); | |
183 | assertFalse(ccdPtDelEdge(&pt, e[5]) == 0); | |
184 | ||
185 | assertTrue(ccdPtDelVertex(&pt, v[1]) == 0); | |
186 | assertFalse(ccdPtDelVertex(&pt, v[0]) == 0); | |
187 | assertFalse(ccdPtDelVertex(&pt, v[2]) == 0); | |
188 | assertFalse(ccdPtDelVertex(&pt, v[3]) == 0); | |
189 | ||
190 | res = ccdPtDelFace(&pt, f[3]); | |
191 | assertTrue(ccdPtDelEdge(&pt, e[2]) == 0); | |
192 | assertTrue(ccdPtDelEdge(&pt, e[3]) == 0); | |
193 | assertTrue(ccdPtDelEdge(&pt, e[5]) == 0); | |
194 | ||
195 | assertTrue(ccdPtDelVertex(&pt, v[0]) == 0); | |
196 | assertTrue(ccdPtDelVertex(&pt, v[2]) == 0); | |
197 | assertTrue(ccdPtDelVertex(&pt, v[3]) == 0); | |
198 | ||
199 | ||
200 | v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); | |
201 | v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); | |
202 | v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); | |
203 | v[3] = ccdPtAddVertexCoords(&pt, 0., 1., 0.); | |
204 | ||
205 | e[0] = ccdPtAddEdge(&pt, v[0], v[1]); | |
206 | e[1] = ccdPtAddEdge(&pt, v[1], v[2]); | |
207 | e[2] = ccdPtAddEdge(&pt, v[2], v[0]); | |
208 | e[3] = ccdPtAddEdge(&pt, v[3], v[0]); | |
209 | e[4] = ccdPtAddEdge(&pt, v[3], v[1]); | |
210 | e[5] = ccdPtAddEdge(&pt, v[3], v[2]); | |
211 | ||
212 | f[0] = ccdPtAddFace(&pt, e[0], e[1], e[2]); | |
213 | f[1] = ccdPtAddFace(&pt, e[3], e[4], e[0]); | |
214 | f[2] = ccdPtAddFace(&pt, e[4], e[5], e[1]); | |
215 | f[3] = ccdPtAddFace(&pt, e[5], e[3], e[2]); | |
216 | ||
217 | ccdPtDestroy(&pt); | |
218 | } | |
219 | ||
220 | TEST(ptNearest) | |
221 | { | |
222 | ccd_pt_t pt; | |
223 | ccd_pt_vertex_t *v[4]; | |
224 | ccd_pt_edge_t *e[6]; | |
225 | ccd_pt_face_t *f[4]; | |
226 | ccd_pt_el_t *nearest; | |
227 | ||
228 | DBG2("------"); | |
229 | ||
230 | ccdPtInit(&pt); | |
231 | ||
232 | v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); | |
233 | v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); | |
234 | v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); | |
235 | v[3] = ccdPtAddVertexCoords(&pt, 0., 1., 0.); | |
236 | ||
237 | e[0] = ccdPtAddEdge(&pt, v[0], v[1]); | |
238 | e[1] = ccdPtAddEdge(&pt, v[1], v[2]); | |
239 | e[2] = ccdPtAddEdge(&pt, v[2], v[0]); | |
240 | e[3] = ccdPtAddEdge(&pt, v[3], v[0]); | |
241 | e[4] = ccdPtAddEdge(&pt, v[3], v[1]); | |
242 | e[5] = ccdPtAddEdge(&pt, v[3], v[2]); | |
243 | ||
244 | f[0] = ccdPtAddFace(&pt, e[0], e[1], e[2]); | |
245 | f[1] = ccdPtAddFace(&pt, e[3], e[4], e[0]); | |
246 | f[2] = ccdPtAddFace(&pt, e[4], e[5], e[1]); | |
247 | f[3] = ccdPtAddFace(&pt, e[5], e[3], e[2]); | |
248 | ||
249 | nearest = ccdPtNearest(&pt); | |
250 | //DBG("nearest->type: %d", nearest->type); | |
251 | //DBG(" ->dist: %lf", nearest->dist); | |
252 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
253 | assertEquals(nearest->type, CCD_PT_FACE); | |
254 | assertEquals(nearest, (ccd_pt_el_t *)f[1]); | |
255 | assertTrue(ccdPtDelFace(&pt, f[1]) == 0); | |
256 | ||
257 | ||
258 | nearest = ccdPtNearest(&pt); | |
259 | //DBG("nearest->type: %d", nearest->type); | |
260 | //DBG(" ->dist: %lf", nearest->dist); | |
261 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
262 | assertEquals(nearest->type, CCD_PT_FACE); | |
263 | assertTrue(nearest == (ccd_pt_el_t *)f[0] | |
264 | || nearest == (ccd_pt_el_t *)f[3]); | |
265 | assertTrue(ccdPtDelFace(&pt, (ccd_pt_face_t *)nearest) == 0); | |
266 | ||
267 | ||
268 | nearest = ccdPtNearest(&pt); | |
269 | //DBG("nearest->type: %d", nearest->type); | |
270 | //DBG(" ->dist: %lf", nearest->dist); | |
271 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
272 | assertEquals(nearest->type, CCD_PT_FACE); | |
273 | assertTrue(nearest == (ccd_pt_el_t *)f[0] | |
274 | || nearest == (ccd_pt_el_t *)f[3]); | |
275 | assertTrue(ccdPtDelFace(&pt, (ccd_pt_face_t *)nearest) == 0); | |
276 | ||
277 | ||
278 | nearest = ccdPtNearest(&pt); | |
279 | //DBG("nearest->type: %d", nearest->type); | |
280 | //DBG(" ->dist: %lf", nearest->dist); | |
281 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
282 | assertEquals(nearest->type, CCD_PT_EDGE); | |
283 | assertTrue(nearest == (ccd_pt_el_t *)e[0] | |
284 | || nearest == (ccd_pt_el_t *)e[3]); | |
285 | assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); | |
286 | ||
287 | ||
288 | nearest = ccdPtNearest(&pt); | |
289 | //DBG("nearest->type: %d", nearest->type); | |
290 | //DBG(" ->dist: %lf", nearest->dist); | |
291 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
292 | assertEquals(nearest->type, CCD_PT_EDGE); | |
293 | assertTrue(nearest == (ccd_pt_el_t *)e[0] | |
294 | || nearest == (ccd_pt_el_t *)e[3]); | |
295 | assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); | |
296 | ||
297 | ||
298 | nearest = ccdPtNearest(&pt); | |
299 | //DBG("nearest->type: %d", nearest->type); | |
300 | //DBG(" ->dist: %lf", nearest->dist); | |
301 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
302 | assertEquals(nearest->type, CCD_PT_FACE); | |
303 | assertEquals(nearest, (ccd_pt_el_t *)f[2]); | |
304 | assertTrue(ccdPtDelFace(&pt, f[2]) == 0); | |
305 | ||
306 | ||
307 | nearest = ccdPtNearest(&pt); | |
308 | //DBG("nearest->type: %d", nearest->type); | |
309 | //DBG(" ->dist: %lf", nearest->dist); | |
310 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
311 | assertEquals(nearest->type, CCD_PT_EDGE); | |
312 | assertTrue(nearest == (ccd_pt_el_t *)e[1] | |
313 | || nearest == (ccd_pt_el_t *)e[4] | |
314 | || nearest == (ccd_pt_el_t *)e[5]); | |
315 | assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); | |
316 | ||
317 | ||
318 | nearest = ccdPtNearest(&pt); | |
319 | //DBG("nearest->type: %d", nearest->type); | |
320 | //DBG(" ->dist: %lf", nearest->dist); | |
321 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
322 | assertEquals(nearest->type, CCD_PT_EDGE); | |
323 | assertTrue(nearest == (ccd_pt_el_t *)e[1] | |
324 | || nearest == (ccd_pt_el_t *)e[4] | |
325 | || nearest == (ccd_pt_el_t *)e[5]); | |
326 | assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); | |
327 | ||
328 | ||
329 | nearest = ccdPtNearest(&pt); | |
330 | //DBG("nearest->type: %d", nearest->type); | |
331 | //DBG(" ->dist: %lf", nearest->dist); | |
332 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
333 | assertEquals(nearest->type, CCD_PT_EDGE); | |
334 | assertTrue(nearest == (ccd_pt_el_t *)e[1] | |
335 | || nearest == (ccd_pt_el_t *)e[4] | |
336 | || nearest == (ccd_pt_el_t *)e[5]); | |
337 | assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); | |
338 | ||
339 | ||
340 | nearest = ccdPtNearest(&pt); | |
341 | //DBG("nearest->type: %d", nearest->type); | |
342 | //DBG(" ->dist: %lf", nearest->dist); | |
343 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
344 | assertEquals(nearest->type, CCD_PT_EDGE); | |
345 | assertTrue(nearest == (ccd_pt_el_t *)e[2]); | |
346 | assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); | |
347 | ||
348 | ||
349 | nearest = ccdPtNearest(&pt); | |
350 | //DBG("nearest->type: %d", nearest->type); | |
351 | //DBG(" ->dist: %lf", nearest->dist); | |
352 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
353 | assertEquals(nearest->type, CCD_PT_VERTEX); | |
354 | assertTrue(nearest == (ccd_pt_el_t *)v[1] | |
355 | || nearest == (ccd_pt_el_t *)v[2] | |
356 | || nearest == (ccd_pt_el_t *)v[3]); | |
357 | assertTrue(ccdPtDelVertex(&pt, (ccd_pt_vertex_t *)nearest) == 0); | |
358 | ||
359 | ||
360 | nearest = ccdPtNearest(&pt); | |
361 | //DBG("nearest->type: %d", nearest->type); | |
362 | //DBG(" ->dist: %lf", nearest->dist); | |
363 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
364 | assertEquals(nearest->type, CCD_PT_VERTEX); | |
365 | assertTrue(nearest == (ccd_pt_el_t *)v[1] | |
366 | || nearest == (ccd_pt_el_t *)v[2] | |
367 | || nearest == (ccd_pt_el_t *)v[3]); | |
368 | assertTrue(ccdPtDelVertex(&pt, (ccd_pt_vertex_t *)nearest) == 0); | |
369 | ||
370 | ||
371 | nearest = ccdPtNearest(&pt); | |
372 | //DBG("nearest->type: %d", nearest->type); | |
373 | //DBG(" ->dist: %lf", nearest->dist); | |
374 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
375 | assertEquals(nearest->type, CCD_PT_VERTEX); | |
376 | assertTrue(nearest == (ccd_pt_el_t *)v[1] | |
377 | || nearest == (ccd_pt_el_t *)v[2] | |
378 | || nearest == (ccd_pt_el_t *)v[3]); | |
379 | assertTrue(ccdPtDelVertex(&pt, (ccd_pt_vertex_t *)nearest) == 0); | |
380 | ||
381 | ||
382 | nearest = ccdPtNearest(&pt); | |
383 | //DBG("nearest->type: %d", nearest->type); | |
384 | //DBG(" ->dist: %lf", nearest->dist); | |
385 | //DBG_VEC3(&nearest->witness, " ->witness: "); | |
386 | assertEquals(nearest->type, CCD_PT_VERTEX); | |
387 | assertTrue(nearest == (ccd_pt_el_t *)v[0]); | |
388 | assertTrue(ccdPtDelVertex(&pt, (ccd_pt_vertex_t *)nearest) == 0); | |
389 | ||
390 | ||
391 | nearest = ccdPtNearest(&pt); | |
392 | assertTrue(nearest == NULL); | |
393 | ||
394 | ccdPtDestroy(&pt); | |
395 | } |
0 | #ifndef TEST_POLYTOPE_H | |
1 | #define TEST_POLYTOPE_H | |
2 | ||
3 | #include <cu/cu.h> | |
4 | ||
5 | TEST(ptSetUp); | |
6 | TEST(ptTearDown); | |
7 | ||
8 | TEST(ptCreate1); | |
9 | TEST(ptCreate2); | |
10 | TEST(ptNearest); | |
11 | ||
12 | TEST_SUITE(TSPt) { | |
13 | TEST_ADD(ptSetUp), | |
14 | ||
15 | TEST_ADD(ptCreate1), | |
16 | TEST_ADD(ptCreate2), | |
17 | TEST_ADD(ptNearest), | |
18 | ||
19 | TEST_ADD(ptTearDown), | |
20 | TEST_SUITE_CLOSURE | |
21 | }; | |
22 | ||
23 | #endif |
0 | # box1.pos: [-0.500000 0.000000 0.000000] | |
1 | # box1->quat: [0.000000 0.000000 0.382683 0.923880] | |
2 | # box2->pos: [0.000000 0.000000 0.000000] | |
3 | # box2->quat: [0.000000 0.000000 0.000000 1.000000] | |
4 | # sep: [0.707107 0.000000 0.000000] | |
5 | # | |
6 | # box1.pos: [-0.500000 0.100000 0.400000] | |
7 | # box1->quat: [0.000000 0.270598 0.270598 0.923880] | |
8 | # box2->pos: [0.000000 0.000000 0.000000] | |
9 | # box2->quat: [0.000000 0.000000 0.000000 1.000000] | |
10 | # sep: [0.633939 0.000000 -0.371353] | |
11 | # | |
12 | # Pen 1: depth: 0.650000 | |
13 | # Pen 1: dir: [1.000000 0.000000 0.000000] | |
14 | # Pen 1: pos: [0.096875 0.000000 0.000000] | |
15 | # | |
16 | # Pen 2: depth: 0.250000 | |
17 | # Pen 2: dir: [-0.000000 0.000000 -1.000000] | |
18 | # Pen 2: pos: [-0.058333 0.250000 0.583333] | |
19 | # | |
20 | # Pen 3: depth: 0.900000 | |
21 | # Pen 3: dir: [0.000000 0.000000 -1.000000] | |
22 | # Pen 3: pos: [0.111506 0.000000 0.050000] | |
23 | # | |
24 | # Pen 4: depth: 0.607107 | |
25 | # Pen 4: dir: [1.000000 0.000000 0.000000] | |
26 | # Pen 4: pos: [-0.153585 0.000000 0.000000] | |
27 | # | |
28 | # Pen 5: depth: 0.429289 | |
29 | # Pen 5: dir: [0.707107 -0.707107 0.000000] | |
30 | # Pen 5: pos: [-0.167157 0.379289 0.000000] | |
31 | # | |
32 | # Pen 6: depth: 0.648412 | |
33 | # Pen 6: dir: [0.862856 0.000000 -0.505449] | |
34 | # Pen 6: pos: [-0.148223 0.055362 0.319638] | |
35 | # | |
36 | # Pen 7: depth: 0.622622 | |
37 | # Pen 7: dir: [1.000000 0.000000 -0.000000] | |
38 | # Pen 7: pos: [-0.095997 0.063593 0.067678] | |
39 | # | |
40 | # Pen 8: depth: 0.053553 | |
41 | # Pen 8: dir: [1.000000 0.000000 0.000000] | |
42 | # Pen 8: pos: [-0.523223 -0.073223 0.020711] | |
43 | # |
0 | # Pen 1: depth: 0.549996 | |
1 | # Pen 1: dir: [0.999992 -0.003902 0.000000] | |
2 | # Pen 1: pos: [0.020284 0.000000 0.000000] | |
3 | # | |
4 | # Pen 2: depth: 0.050000 | |
5 | # Pen 2: dir: [0.999992 -0.003902 0.000000] | |
6 | # Pen 2: pos: [0.253480 0.000000 0.025000] | |
7 | # | |
8 | # Pen 3: depth: 0.030994 | |
9 | # Pen 3: dir: [0.950248 0.311493 0.000000] | |
10 | # Pen 3: pos: [0.246546 0.420744 0.000000] | |
11 | # | |
12 | # Pen 4: depth: 0.033436 | |
13 | # Pen 4: dir: [0.976101 0.217308 0.001900] | |
14 | # Pen 4: pos: [0.243648 0.480401 0.450000] | |
15 | # | |
16 | # Pen 5: depth: 0.142160 | |
17 | # Pen 5: dir: [0.968442 0.249235 0.001146] | |
18 | # Pen 5: pos: [0.190887 0.421462 0.605496] | |
19 | # | |
20 | # Pen 6: depth: 0.179282 | |
21 | # Pen 6: dir: [0.999995 0.001057 0.002913] | |
22 | # Pen 6: pos: [0.176026 0.036944 0.488189] | |
23 | # | |
24 | # Pen 7: depth: 0.750000 | |
25 | # Pen 7: dir: [-0.853795 -0.143509 -0.500438] | |
26 | # Pen 7: pos: [0.572744 0.014828 0.562324] | |
27 | # | |
28 | # Pen 8: depth: 0.142666 | |
29 | # Pen 8: dir: [-0.475515 -0.841074 0.257839] | |
30 | # Pen 8: pos: [0.824886 0.230213 0.463136] | |
31 | # |
0 | # Pen 1: depth: 0.750000 | |
1 | # Pen 1: dir: [0.000000 0.000000 1.000000] | |
2 | # Pen 1: pos: [0.004079 -0.012238 0.009615] | |
3 | # | |
4 | # Pen 2: depth: 0.531931 | |
5 | # Pen 2: dir: [-0.926428 -0.376463 -0.002666] | |
6 | # Pen 2: pos: [0.218566 0.072232 0.025000] | |
7 | # | |
8 | # Pen 3: depth: 0.645740 | |
9 | # Pen 3: dir: [-0.500000 -0.146447 -0.853553] | |
10 | # Pen 3: pos: [0.177594 0.070484 0.186987] | |
11 | # | |
12 | # Pen 4: depth: 0.104445 | |
13 | # Pen 4: dir: [-0.482095 0.866317 0.130685] | |
14 | # Pen 4: pos: [0.123724 0.348390 0.269312] | |
15 | # | |
16 | # Pen 5: depth: 0.093082 | |
17 | # Pen 5: dir: [0.034600 -0.999228 -0.018627] | |
18 | # Pen 5: pos: [0.311257 -0.203923 -0.064270] | |
19 | # | |
20 | # Pen 6: depth: 0.198749 | |
21 | # Pen 6: dir: [0.411370 -0.911372 0.013223] | |
22 | # Pen 6: pos: [0.405836 -0.130066 0.121441] | |
23 | # |
0 | # box1.pos: [-0.500000 0.000000 0.000000] | |
1 | # box1->quat: [0.000000 0.000000 0.382683 0.923880] | |
2 | # box2->pos: [0.000000 0.000000 0.000000] | |
3 | # box2->quat: [0.000000 0.000000 0.000000 1.000000] | |
4 | # sep: [0.707107 0.000000 0.000000] | |
5 | # | |
6 | # box1.pos: [-0.500000 0.100000 0.400000] | |
7 | # box1->quat: [0.000000 0.270598 0.270598 0.923880] | |
8 | # box2->pos: [0.000000 0.000000 0.000000] | |
9 | # box2->quat: [0.000000 0.000000 0.000000 1.000000] | |
10 | # sep: [0.633939 0.000000 -0.371353] | |
11 | # | |
12 | # Pen 1: depth: 0.650000 | |
13 | # Pen 1: dir: [1.000000 0.000000 0.000000] | |
14 | # Pen 1: pos: [0.175000 0.000000 0.000000] | |
15 | # | |
16 | # Pen 2: depth: 0.250000 | |
17 | # Pen 2: dir: [-0.000000 0.000000 -1.000000] | |
18 | # Pen 2: pos: [-0.033333 0.250000 0.600000] | |
19 | # | |
20 | # Pen 3: depth: 0.900000 | |
21 | # Pen 3: dir: [0.000000 0.000000 -1.000000] | |
22 | # Pen 3: pos: [0.100000 0.000000 0.050000] | |
23 | # | |
24 | # Pen 4: depth: 0.607107 | |
25 | # Pen 4: dir: [1.000000 0.000000 0.000000] | |
26 | # Pen 4: pos: [-0.096447 0.000000 0.000000] | |
27 | # | |
28 | # Pen 5: depth: 0.429289 | |
29 | # Pen 5: dir: [0.707107 -0.707107 0.000000] | |
30 | # Pen 5: pos: [-0.222183 0.322183 0.000000] | |
31 | # | |
32 | # Pen 6: depth: 0.648412 | |
33 | # Pen 6: dir: [0.862856 0.000000 -0.505449] | |
34 | # Pen 6: pos: [-0.163060 0.012676 0.263060] | |
35 | # | |
36 | # Pen 7: depth: 0.622928 | |
37 | # Pen 7: dir: [0.999509 0.028016 -0.014008] | |
38 | # Pen 7: pos: [-0.145374 0.170833 0.176732] | |
39 | # | |
40 | # Pen 8: depth: 0.053553 | |
41 | # Pen 8: dir: [1.000000 0.000000 0.000000] | |
42 | # Pen 8: pos: [-0.480217 -0.140652 0.000000] | |
43 | # | |
44 | # Pen 9: depth: 0.020000 | |
45 | # Pen 9: dir: [0.000000 1.000000 0.000000] | |
46 | # Pen 9: pos: [0.000000 0.490000 0.000000] | |
47 | # | |
48 | # Pen 10: depth: 0.012000 | |
49 | # Pen 10: dir: [-0.000000 1.000000 0.000000] | |
50 | # Pen 10: pos: [0.200000 0.492000 0.000000] | |
51 | # |
0 | # Pen 1: depth: 0.550000 | |
1 | # Pen 1: dir: [1.000000 0.000000 0.000000] | |
2 | # Pen 1: pos: [-0.025000 0.000000 0.000000] | |
3 | # | |
4 | # Pen 2: depth: 0.050000 | |
5 | # Pen 2: dir: [1.000000 0.000000 0.000000] | |
6 | # Pen 2: pos: [0.225000 0.000000 0.000000] | |
7 | # | |
8 | # Pen 3: depth: 0.038532 | |
9 | # Pen 3: dir: [0.788956 0.614450 0.000000] | |
10 | # Pen 3: pos: [0.238587 0.477175 0.000000] | |
11 | # | |
12 | # Pen 4: depth: 0.038654 | |
13 | # Pen 4: dir: [0.779134 0.626832 -0.005696] | |
14 | # Pen 4: pos: [0.238603 0.477206 0.340909] | |
15 | # | |
16 | # Pen 5: depth: 0.166653 | |
17 | # Pen 5: dir: [0.734126 0.679013 -0.000000] | |
18 | # Pen 5: pos: [0.208320 0.416640 0.595113] | |
19 | # | |
20 | # Pen 6: depth: 0.180673 | |
21 | # Pen 6: dir: [1.000000 0.000003 -0.000000] | |
22 | # Pen 6: pos: [0.192142 0.009404 0.479162] | |
23 | # | |
24 | # Pen 7: depth: 1.321922 | |
25 | # Pen 7: dir: [-0.897996 -0.063457 0.435403] | |
26 | # Pen 7: pos: [0.531929 -0.046446 0.867546] | |
27 | # | |
28 | # Pen 8: depth: 0.142813 | |
29 | # Pen 8: dir: [-0.476782 -0.840534 0.257259] | |
30 | # Pen 8: pos: [0.776128 0.285646 0.436629] | |
31 | # |
0 | # Pen 1: depth: 0.450000 | |
1 | # Pen 1: dir: [0.000000 0.000000 1.000000] | |
2 | # Pen 1: pos: [0.000000 0.000000 0.025000] | |
3 | # | |
4 | # Pen 2: depth: 0.533732 | |
5 | # Pen 2: dir: [-0.952492 -0.304562 0.000000] | |
6 | # Pen 2: pos: [0.176471 0.058824 0.166667] | |
7 | # | |
8 | # Pen 3: depth: 0.720933 | |
9 | # Pen 3: dir: [-0.947406 -0.320033 0.000085] | |
10 | # Pen 3: pos: [0.198747 0.066309 0.050800] | |
11 | # | |
12 | # Pen 4: depth: 0.106076 | |
13 | # Pen 4: dir: [-0.524820 0.835278 0.163936] | |
14 | # Pen 4: pos: [0.138692 0.362418 0.320024] | |
15 | # | |
16 | # Pen 5: depth: 0.103863 | |
17 | # Pen 5: dir: [0.291494 -0.956567 -0.003314] | |
18 | # Pen 5: pos: [0.337721 -0.209314 -0.094587] | |
19 | # | |
20 | # Pen 6: depth: 0.202625 | |
21 | # Pen 6: dir: [0.347225 -0.937782 -0.000000] | |
22 | # Pen 6: pos: [0.399554 -0.164780 0.199941] | |
23 | # |
0 | ptCreate1 :: ------ | |
1 | ptCreate1 :: e[0]->dist: 0.200000 | |
2 | ptCreate1 :: ->witness: [0.200000 -0.400000 0.000000] | |
3 | ptCreate1 :: e[1]->dist: 0.500000 | |
4 | ptCreate1 :: ->witness: [0.500000 0.000000 0.500000] | |
5 | ptCreate1 :: e[2]->dist: 0.666667 | |
6 | ptCreate1 :: ->witness: [-0.333333 -0.333333 0.666667] | |
7 | ptCreate1 :: f->dist: 0.166667 | |
8 | ptCreate1 :: ->witness: [0.166667 -0.333333 0.166667] | |
9 | ptCreate2 :: ------ | |
10 | ptCreate2 :: v[0]->dist: 2.000000 | |
11 | ptCreate2 :: ->witness: [-1.000000 -1.000000 0.000000] | |
12 | ptCreate2 :: v[1]->dist: 1.000000 | |
13 | ptCreate2 :: ->witness: [1.000000 0.000000 0.000000] | |
14 | ptCreate2 :: v[2]->dist: 1.000000 | |
15 | ptCreate2 :: ->witness: [0.000000 0.000000 1.000000] | |
16 | ptCreate2 :: v[3]->dist: 1.000000 | |
17 | ptCreate2 :: ->witness: [0.000000 1.000000 0.000000] | |
18 | ptCreate2 :: e[0]->dist: 0.200000 | |
19 | ptCreate2 :: ->witness: [0.200000 -0.400000 0.000000] | |
20 | ptCreate2 :: e[1]->dist: 0.500000 | |
21 | ptCreate2 :: ->witness: [0.500000 0.000000 0.500000] | |
22 | ptCreate2 :: e[2]->dist: 0.666667 | |
23 | ptCreate2 :: ->witness: [-0.333333 -0.333333 0.666667] | |
24 | ptCreate2 :: e[3]->dist: 0.200000 | |
25 | ptCreate2 :: ->witness: [-0.400000 0.200000 0.000000] | |
26 | ptCreate2 :: e[4]->dist: 0.500000 | |
27 | ptCreate2 :: ->witness: [0.500000 0.500000 0.000000] | |
28 | ptCreate2 :: e[5]->dist: 0.500000 | |
29 | ptCreate2 :: ->witness: [0.000000 0.500000 0.500000] | |
30 | ptCreate2 :: f[0]->dist: 0.166667 | |
31 | ptCreate2 :: ->witness: [0.166667 -0.333333 0.166667] | |
32 | ptCreate2 :: f[1]->dist: 0.000000 | |
33 | ptCreate2 :: ->witness: [0.000000 0.000000 0.000000] | |
34 | ptCreate2 :: f[2]->dist: 0.333333 | |
35 | ptCreate2 :: ->witness: [0.333333 0.333333 0.333333] | |
36 | ptCreate2 :: f[3]->dist: 0.166667 | |
37 | ptCreate2 :: ->witness: [-0.333333 0.166667 0.166667] | |
38 | ptNearest :: ------ |
0 | #include <stdio.h> | |
1 | #include <cu/cu.h> | |
2 | #include "support.h" | |
3 | #include <ccd/ccd.h> | |
4 | ||
5 | TEST(spheresphereSetUp) | |
6 | { | |
7 | } | |
8 | ||
9 | TEST(spheresphereTearDown) | |
10 | { | |
11 | } | |
12 | ||
13 | TEST(spheresphereAlignedX) | |
14 | { | |
15 | ccd_t ccd; | |
16 | CCD_SPHERE(s1); | |
17 | CCD_SPHERE(s2); | |
18 | size_t i; | |
19 | int res; | |
20 | ||
21 | CCD_INIT(&ccd); | |
22 | ccd.support1 = ccdSupport; | |
23 | ccd.support2 = ccdSupport; | |
24 | ||
25 | s1.radius = 0.35; | |
26 | s2.radius = .5; | |
27 | ||
28 | ccdVec3Set(&s1.pos, -5., 0., 0.); | |
29 | for (i = 0; i < 100; i++){ | |
30 | res = ccdGJKIntersect(&s1, &s2, &ccd); | |
31 | ||
32 | if (i < 42 || i > 58){ | |
33 | assertFalse(res); | |
34 | }else{ | |
35 | assertTrue(res); | |
36 | } | |
37 | ||
38 | s1.pos.v[0] += 0.1; | |
39 | } | |
40 | } | |
41 | ||
42 | TEST(spheresphereAlignedY) | |
43 | { | |
44 | ccd_t ccd; | |
45 | CCD_SPHERE(s1); | |
46 | CCD_SPHERE(s2); | |
47 | size_t i; | |
48 | int res; | |
49 | ||
50 | CCD_INIT(&ccd); | |
51 | ccd.support1 = ccdSupport; | |
52 | ccd.support2 = ccdSupport; | |
53 | ||
54 | s1.radius = 0.35; | |
55 | s2.radius = .5; | |
56 | ||
57 | ccdVec3Set(&s1.pos, 0., -5., 0.); | |
58 | for (i = 0; i < 100; i++){ | |
59 | res = ccdGJKIntersect(&s1, &s2, &ccd); | |
60 | ||
61 | if (i < 42 || i > 58){ | |
62 | assertFalse(res); | |
63 | }else{ | |
64 | assertTrue(res); | |
65 | } | |
66 | ||
67 | s1.pos.v[1] += 0.1; | |
68 | } | |
69 | } | |
70 | ||
71 | TEST(spheresphereAlignedZ) | |
72 | { | |
73 | ccd_t ccd; | |
74 | CCD_SPHERE(s1); | |
75 | CCD_SPHERE(s2); | |
76 | size_t i; | |
77 | int res; | |
78 | ||
79 | CCD_INIT(&ccd); | |
80 | ccd.support1 = ccdSupport; | |
81 | ccd.support2 = ccdSupport; | |
82 | ||
83 | s1.radius = 0.35; | |
84 | s2.radius = .5; | |
85 | ||
86 | ccdVec3Set(&s1.pos, 0., 0., -5.); | |
87 | for (i = 0; i < 100; i++){ | |
88 | res = ccdGJKIntersect(&s1, &s2, &ccd); | |
89 | ||
90 | if (i < 42 || i > 58){ | |
91 | assertFalse(res); | |
92 | }else{ | |
93 | assertTrue(res); | |
94 | } | |
95 | ||
96 | s1.pos.v[2] += 0.1; | |
97 | } | |
98 | } |
0 | #ifndef SPHERE_SPHERE | |
1 | #define SPHERE_SPHERE | |
2 | ||
3 | #include <cu/cu.h> | |
4 | ||
5 | TEST(spheresphereSetUp); | |
6 | TEST(spheresphereTearDown); | |
7 | ||
8 | TEST(spheresphereAlignedX); | |
9 | TEST(spheresphereAlignedY); | |
10 | TEST(spheresphereAlignedZ); | |
11 | ||
12 | TEST_SUITE(TSSphereSphere) { | |
13 | TEST_ADD(spheresphereSetUp), | |
14 | ||
15 | TEST_ADD(spheresphereAlignedX), | |
16 | TEST_ADD(spheresphereAlignedY), | |
17 | TEST_ADD(spheresphereAlignedZ), | |
18 | ||
19 | TEST_ADD(spheresphereTearDown), | |
20 | TEST_SUITE_CLOSURE | |
21 | }; | |
22 | ||
23 | #endif |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #include <stdio.h> | |
18 | #include <ccd/ccd.h> | |
19 | #include <ccd/vec3.h> | |
20 | #include "support.h" | |
21 | ||
22 | void ccdSupport(const void *_obj, const ccd_vec3_t *_dir, | |
23 | ccd_vec3_t *v) | |
24 | { | |
25 | // Support function is made according to Gino van den Bergen's paper | |
26 | // A Fast and Robust CCD Implementation for Collision Detection of | |
27 | // Convex Objects | |
28 | ||
29 | ccd_obj_t *obj = (ccd_obj_t *)_obj; | |
30 | ccd_vec3_t dir; | |
31 | ccd_quat_t qinv; | |
32 | ||
33 | ccdVec3Copy(&dir, _dir); | |
34 | ccdQuatInvert2(&qinv, &obj->quat); | |
35 | ||
36 | ccdQuatRotVec(&dir, &qinv); | |
37 | ||
38 | if (obj->type == CCD_OBJ_BOX){ | |
39 | ccd_box_t *box = (ccd_box_t *)obj; | |
40 | ccdVec3Set(v, ccdSign(ccdVec3X(&dir)) * box->x * CCD_REAL(0.5), | |
41 | ccdSign(ccdVec3Y(&dir)) * box->y * CCD_REAL(0.5), | |
42 | ccdSign(ccdVec3Z(&dir)) * box->z * CCD_REAL(0.5)); | |
43 | }else if (obj->type == CCD_OBJ_SPHERE){ | |
44 | ccd_sphere_t *sphere = (ccd_sphere_t *)obj; | |
45 | ccd_real_t len; | |
46 | ||
47 | len = ccdVec3Len2(&dir); | |
48 | if (len - CCD_EPS > CCD_ZERO){ | |
49 | ccdVec3Copy(v, &dir); | |
50 | ccdVec3Scale(v, sphere->radius / CCD_SQRT(len)); | |
51 | }else{ | |
52 | ccdVec3Set(v, CCD_ZERO, CCD_ZERO, CCD_ZERO); | |
53 | } | |
54 | }else if (obj->type == CCD_OBJ_CYL){ | |
55 | ccd_cyl_t *cyl = (ccd_cyl_t *)obj; | |
56 | ccd_real_t zdist, rad; | |
57 | ||
58 | zdist = dir.v[0] * dir.v[0] + dir.v[1] * dir.v[1]; | |
59 | zdist = CCD_SQRT(zdist); | |
60 | if (ccdIsZero(zdist)){ | |
61 | ccdVec3Set(v, CCD_ZERO, CCD_ZERO, | |
62 | ccdSign(ccdVec3Z(&dir)) * cyl->height * CCD_REAL(0.5)); | |
63 | }else{ | |
64 | rad = cyl->radius / zdist; | |
65 | ||
66 | ccdVec3Set(v, rad * ccdVec3X(&dir), | |
67 | rad * ccdVec3Y(&dir), | |
68 | ccdSign(ccdVec3Z(&dir)) * cyl->height * CCD_REAL(0.5)); | |
69 | } | |
70 | } | |
71 | ||
72 | // transform support vertex | |
73 | ccdQuatRotVec(v, &obj->quat); | |
74 | ccdVec3Add(v, &obj->pos); | |
75 | } | |
76 | ||
77 | void ccdObjCenter(const void *_obj, ccd_vec3_t *center) | |
78 | { | |
79 | ccd_obj_t *obj = (ccd_obj_t *)_obj; | |
80 | ||
81 | ccdVec3Set(center, CCD_ZERO, CCD_ZERO, CCD_ZERO); | |
82 | // rotation is not needed | |
83 | ccdVec3Add(center, &obj->pos); | |
84 | } |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | /*** | |
18 | * Some support() functions for some convex shapes. | |
19 | */ | |
20 | ||
21 | #ifndef __CCD_SUPPORT_H__ | |
22 | #define __CCD_SUPPORT_H__ | |
23 | ||
24 | #include <ccd/quat.h> | |
25 | ||
26 | #ifdef __cplusplus | |
27 | extern "C" { | |
28 | #endif /* __cplusplus */ | |
29 | ||
30 | #define CCD_OBJ_BOX 1 | |
31 | #define CCD_OBJ_SPHERE 2 | |
32 | #define CCD_OBJ_CYL 3 | |
33 | ||
34 | #define __CCD_OBJ__ \ | |
35 | int type; \ | |
36 | ccd_vec3_t pos; \ | |
37 | ccd_quat_t quat; | |
38 | ||
39 | struct _ccd_obj_t { | |
40 | __CCD_OBJ__ | |
41 | }; | |
42 | typedef struct _ccd_obj_t ccd_obj_t; | |
43 | ||
44 | struct _ccd_box_t { | |
45 | __CCD_OBJ__ | |
46 | ccd_real_t x, y, z; //!< Lengths of box's edges | |
47 | }; | |
48 | typedef struct _ccd_box_t ccd_box_t; | |
49 | ||
50 | struct _ccd_sphere_t { | |
51 | __CCD_OBJ__ | |
52 | ccd_real_t radius; | |
53 | }; | |
54 | typedef struct _ccd_sphere_t ccd_sphere_t; | |
55 | ||
56 | struct _ccd_cyl_t { | |
57 | __CCD_OBJ__ | |
58 | ccd_real_t radius; | |
59 | ccd_real_t height; | |
60 | }; | |
61 | typedef struct _ccd_cyl_t ccd_cyl_t; | |
62 | ||
63 | ||
64 | #define CCD_BOX(name) \ | |
65 | ccd_box_t name = { .type = CCD_OBJ_BOX, \ | |
66 | .pos = { .v = { 0., 0., 0. } }, \ | |
67 | .quat = { .q = { 0., 0., 0., 1. } }, \ | |
68 | .x = 0., \ | |
69 | .y = 0., \ | |
70 | .z = 0. } | |
71 | ||
72 | #define CCD_SPHERE(name) \ | |
73 | ccd_sphere_t name = { .type = CCD_OBJ_SPHERE, \ | |
74 | .pos = { .v = { 0., 0., 0. } }, \ | |
75 | .quat = { .q = { 0., 0., 0., 1. } }, \ | |
76 | .radius = 0. } | |
77 | ||
78 | #define CCD_CYL(name) \ | |
79 | ccd_cyl_t name = { .type = CCD_OBJ_CYL, \ | |
80 | .pos = { .v = { 0., 0., 0. } }, \ | |
81 | .quat = { .q = { 0., 0., 0., 1. } }, \ | |
82 | .radius = 0., \ | |
83 | .height = 0. } | |
84 | ||
85 | /** | |
86 | * Returns supporting vertex via v. | |
87 | * Supporting vertex is fathest vertex from object in direction dir. | |
88 | */ | |
89 | void ccdSupport(const void *obj, const ccd_vec3_t *dir, | |
90 | ccd_vec3_t *v); | |
91 | ||
92 | /** | |
93 | * Returns center of object. | |
94 | */ | |
95 | void ccdObjCenter(const void *obj, ccd_vec3_t *center); | |
96 | ||
97 | #ifdef __cplusplus | |
98 | } /* extern "C" */ | |
99 | #endif /* __cplusplus */ | |
100 | ||
101 | #endif /* __CCD_SUPPORT_H__ */ |
0 | #include <stdio.h> | |
1 | #include <cu/cu.h> | |
2 | #include <ccd/vec3.h> | |
3 | ||
4 | TEST(vec3SetUp) | |
5 | { | |
6 | } | |
7 | ||
8 | TEST(vec3TearDown) | |
9 | { | |
10 | } | |
11 | ||
12 | ||
13 | TEST(vec3PointSegmentDist) | |
14 | { | |
15 | ccd_vec3_t P, a, b, w, ew; | |
16 | ccd_real_t dist; | |
17 | ||
18 | ccdVec3Set(&a, 0., 0., 0.); | |
19 | ccdVec3Set(&b, 1., 0., 0.); | |
20 | ||
21 | // extereme w == a | |
22 | ccdVec3Set(&P, -1., 0., 0.); | |
23 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
24 | assertTrue(ccdEq(dist, 1.)); | |
25 | assertTrue(ccdVec3Eq(&w, &a)); | |
26 | ||
27 | ccdVec3Set(&P, -0.5, 0., 0.); | |
28 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
29 | assertTrue(ccdEq(dist, 0.5 * 0.5)); | |
30 | assertTrue(ccdVec3Eq(&w, &a)); | |
31 | ||
32 | ccdVec3Set(&P, -0.1, 0., 0.); | |
33 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
34 | assertTrue(ccdEq(dist, .1 * .1)); | |
35 | assertTrue(ccdVec3Eq(&w, &a)); | |
36 | ||
37 | ccdVec3Set(&P, 0., 0., 0.); | |
38 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
39 | assertTrue(ccdEq(dist, 0.)); | |
40 | assertTrue(ccdVec3Eq(&w, &a)); | |
41 | ||
42 | ccdVec3Set(&P, -1., 1., 0.); | |
43 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
44 | assertTrue(ccdEq(dist, 2.)); | |
45 | assertTrue(ccdVec3Eq(&w, &a)); | |
46 | ||
47 | ccdVec3Set(&P, -0.5, 0.5, 0.); | |
48 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
49 | assertTrue(ccdEq(dist, 0.5)); | |
50 | assertTrue(ccdVec3Eq(&w, &a)); | |
51 | ||
52 | ccdVec3Set(&P, -0.1, -1., 2.); | |
53 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
54 | assertTrue(ccdEq(dist, 5.01)); | |
55 | assertTrue(ccdVec3Eq(&w, &a)); | |
56 | ||
57 | ||
58 | // extereme w == b | |
59 | ccdVec3Set(&P, 2., 0., 0.); | |
60 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
61 | assertTrue(ccdEq(dist, 1.)); | |
62 | assertTrue(ccdVec3Eq(&w, &b)); | |
63 | ||
64 | ccdVec3Set(&P, 1.5, 0., 0.); | |
65 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
66 | assertTrue(ccdEq(dist, 0.5 * 0.5)); | |
67 | assertTrue(ccdVec3Eq(&w, &b)); | |
68 | ||
69 | ccdVec3Set(&P, 1.1, 0., 0.); | |
70 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
71 | assertTrue(ccdEq(dist, .1 * .1)); | |
72 | assertTrue(ccdVec3Eq(&w, &b)); | |
73 | ||
74 | ccdVec3Set(&P, 1., 0., 0.); | |
75 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
76 | assertTrue(ccdEq(dist, 0.)); | |
77 | assertTrue(ccdVec3Eq(&w, &b)); | |
78 | ||
79 | ccdVec3Set(&P, 2., 1., 0.); | |
80 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
81 | assertTrue(ccdEq(dist, 2.)); | |
82 | assertTrue(ccdVec3Eq(&w, &b)); | |
83 | ||
84 | ccdVec3Set(&P, 1.5, 0.5, 0.); | |
85 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
86 | assertTrue(ccdEq(dist, 0.5)); | |
87 | assertTrue(ccdVec3Eq(&w, &b)); | |
88 | ||
89 | ccdVec3Set(&P, 1.1, -1., 2.); | |
90 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
91 | assertTrue(ccdEq(dist, 5.01)); | |
92 | assertTrue(ccdVec3Eq(&w, &b)); | |
93 | ||
94 | // inside segment | |
95 | ccdVec3Set(&P, .5, 0., 0.); | |
96 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
97 | assertTrue(ccdEq(dist, 0.)); | |
98 | assertTrue(ccdVec3Eq(&w, &P)); | |
99 | ||
100 | ccdVec3Set(&P, .9, 0., 0.); | |
101 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
102 | assertTrue(ccdEq(dist, 0.)); | |
103 | assertTrue(ccdVec3Eq(&w, &P)); | |
104 | ||
105 | ccdVec3Set(&P, .5, 1., 0.); | |
106 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
107 | assertTrue(ccdEq(dist, 1.)); | |
108 | ccdVec3Set(&ew, 0.5, 0., 0.); | |
109 | assertTrue(ccdVec3Eq(&w, &ew)); | |
110 | ||
111 | ccdVec3Set(&P, .5, 1., 1.); | |
112 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
113 | assertTrue(ccdEq(dist, 2.)); | |
114 | ccdVec3Set(&ew, 0.5, 0., 0.); | |
115 | assertTrue(ccdVec3Eq(&w, &ew)); | |
116 | ||
117 | ||
118 | ||
119 | ccdVec3Set(&a, -.5, 2., 1.); | |
120 | ccdVec3Set(&b, 1., 1.5, 0.5); | |
121 | ||
122 | // extereme w == a | |
123 | ccdVec3Set(&P, -10., 0., 0.); | |
124 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
125 | assertTrue(ccdEq(dist, 9.5 * 9.5 + 2. * 2. + 1.)); | |
126 | assertTrue(ccdVec3Eq(&w, &a)); | |
127 | ||
128 | ccdVec3Set(&P, -10., 9.2, 3.4); | |
129 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
130 | assertTrue(ccdEq(dist, 9.5 * 9.5 + 7.2 * 7.2 + 2.4 * 2.4)); | |
131 | assertTrue(ccdVec3Eq(&w, &a)); | |
132 | ||
133 | // extereme w == b | |
134 | ccdVec3Set(&P, 10., 0., 0.); | |
135 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
136 | assertTrue(ccdEq(dist, 9. * 9. + 1.5 * 1.5 + 0.5 * 0.5)); | |
137 | assertTrue(ccdVec3Eq(&w, &b)); | |
138 | ||
139 | ccdVec3Set(&P, 10., 9.2, 3.4); | |
140 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
141 | assertTrue(ccdEq(dist, 9. * 9. + 7.7 * 7.7 + 2.9 * 2.9)); | |
142 | assertTrue(ccdVec3Eq(&w, &b)); | |
143 | ||
144 | // inside ab | |
145 | ccdVec3Set(&a, -.1, 1., 1.); | |
146 | ccdVec3Set(&b, 1., 1., 1.); | |
147 | ccdVec3Set(&P, 0., 0., 0.); | |
148 | dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); | |
149 | assertTrue(ccdEq(dist, 2.)); | |
150 | ccdVec3Set(&ew, 0., 1., 1.); | |
151 | assertTrue(ccdVec3Eq(&w, &ew)); | |
152 | } | |
153 | ||
154 | ||
155 | TEST(vec3PointTriDist) | |
156 | { | |
157 | ccd_vec3_t P, a, b, c, w, P0; | |
158 | ccd_real_t dist; | |
159 | ||
160 | ccdVec3Set(&a, -1., 0., 0.); | |
161 | ccdVec3Set(&b, 0., 1., 1.); | |
162 | ccdVec3Set(&c, -1., 0., 1.); | |
163 | ||
164 | ccdVec3Set(&P, -1., 0., 0.); | |
165 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
166 | assertTrue(ccdEq(dist, 0.)); | |
167 | assertTrue(ccdVec3Eq(&w, &a)); | |
168 | ||
169 | ccdVec3Set(&P, 0., 1., 1.); | |
170 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
171 | assertTrue(ccdEq(dist, 0.)); | |
172 | assertTrue(ccdVec3Eq(&w, &b)); | |
173 | ||
174 | ccdVec3Set(&P, -1., 0., 1.); | |
175 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
176 | assertTrue(ccdEq(dist, 0.)); | |
177 | assertTrue(ccdVec3Eq(&w, &c)); | |
178 | ||
179 | ccdVec3Set(&P, 0., 0., 0.); | |
180 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, NULL); | |
181 | assertTrue(ccdEq(dist, 2./3.)); | |
182 | ||
183 | ||
184 | // region 4 | |
185 | ccdVec3Set(&P, -2., 0., 0.); | |
186 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
187 | assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &a))); | |
188 | assertTrue(ccdVec3Eq(&w, &a)); | |
189 | ccdVec3Set(&P, -2., 0.2, -1.); | |
190 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
191 | assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &a))); | |
192 | assertTrue(ccdVec3Eq(&w, &a)); | |
193 | ||
194 | // region 2 | |
195 | ccdVec3Set(&P, -1.3, 0., 1.2); | |
196 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
197 | assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &c))); | |
198 | assertTrue(ccdVec3Eq(&w, &c)); | |
199 | ccdVec3Set(&P, -1.2, 0.2, 1.1); | |
200 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
201 | assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &c))); | |
202 | assertTrue(ccdVec3Eq(&w, &c)); | |
203 | ||
204 | // region 6 | |
205 | ccdVec3Set(&P, 0.3, 1., 1.); | |
206 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
207 | assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &b))); | |
208 | assertTrue(ccdVec3Eq(&w, &b)); | |
209 | ccdVec3Set(&P, .1, 1., 1.); | |
210 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
211 | assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &b))); | |
212 | assertTrue(ccdVec3Eq(&w, &b)); | |
213 | ||
214 | // region 1 | |
215 | ccdVec3Set(&P, 0., 1., 2.); | |
216 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
217 | assertTrue(ccdEq(dist, 1.)); | |
218 | assertTrue(ccdVec3Eq(&w, &b)); | |
219 | ccdVec3Set(&P, -1., 0., 2.); | |
220 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
221 | assertTrue(ccdEq(dist, 1.)); | |
222 | assertTrue(ccdVec3Eq(&w, &c)); | |
223 | ccdVec3Set(&P, -0.5, 0.5, 2.); | |
224 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
225 | assertTrue(ccdEq(dist, 1.)); | |
226 | ccdVec3Set(&P0, -0.5, 0.5, 1.); | |
227 | assertTrue(ccdVec3Eq(&w, &P0)); | |
228 | ||
229 | // region 3 | |
230 | ccdVec3Set(&P, -2., -1., 0.7); | |
231 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
232 | assertTrue(ccdEq(dist, 2.)); | |
233 | ccdVec3Set(&P0, -1., 0., 0.7); | |
234 | assertTrue(ccdVec3Eq(&w, &P0)); | |
235 | ||
236 | // region 5 | |
237 | ccdVec3Set(&P, 0., 0., 0.); | |
238 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
239 | assertTrue(ccdEq(dist, 2./3.)); | |
240 | ccdVec3Set(&P0, -2./3., 1./3., 1./3.); | |
241 | assertTrue(ccdVec3Eq(&w, &P0)); | |
242 | ||
243 | // region 0 | |
244 | ccdVec3Set(&P, -0.5, 0.5, 0.5); | |
245 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
246 | assertTrue(ccdEq(dist, 0.)); | |
247 | assertTrue(ccdVec3Eq(&w, &P)); | |
248 | ccdVec3Set(&P, -0.5, 0.5, 0.7); | |
249 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
250 | assertTrue(ccdEq(dist, 0.)); | |
251 | assertTrue(ccdVec3Eq(&w, &P)); | |
252 | ccdVec3Set(&P, -0.5, 0.5, 0.9); | |
253 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
254 | assertTrue(ccdEq(dist, 0.)); | |
255 | assertTrue(ccdVec3Eq(&w, &P)); | |
256 | ||
257 | ccdVec3Set(&P, 0., 0., 0.5); | |
258 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
259 | assertTrue(ccdEq(dist, 0.5)); | |
260 | ccdVec3Set(&P0, -.5, .5, .5); | |
261 | assertTrue(ccdVec3Eq(&w, &P0)); | |
262 | ||
263 | ccdVec3Set(&a, -1., 0., 0.); | |
264 | ccdVec3Set(&b, 0., 1., -1.); | |
265 | ccdVec3Set(&c, 0., 1., 1.); | |
266 | ccdVec3Set(&P, 0., 0., 0.); | |
267 | dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); | |
268 | assertTrue(ccdEq(dist, 0.5)); | |
269 | ccdVec3Set(&P0, -.5, .5, 0.); | |
270 | assertTrue(ccdVec3Eq(&w, &P0)); | |
271 | //fprintf(stderr, "dist: %lf\n", dist); | |
272 | } |
0 | #ifndef TEST_VEC3_H | |
1 | #define TEST_VEC3_H | |
2 | ||
3 | #include <cu/cu.h> | |
4 | ||
5 | TEST(vec3SetUp); | |
6 | TEST(vec3TearDown); | |
7 | TEST(vec3PointSegmentDist); | |
8 | TEST(vec3PointTriDist); | |
9 | ||
10 | TEST_SUITE(TSVec3) { | |
11 | TEST_ADD(vec3SetUp), | |
12 | ||
13 | TEST_ADD(vec3PointSegmentDist), | |
14 | TEST_ADD(vec3PointTriDist), | |
15 | ||
16 | TEST_ADD(vec3TearDown), | |
17 | TEST_SUITE_CLOSURE | |
18 | }; | |
19 | #endif |
0 | /*** | |
1 | * libccd | |
2 | * --------------------------------- | |
3 | * Copyright (c)2010 Daniel Fiser <danfis@danfis.cz> | |
4 | * | |
5 | * | |
6 | * This file is part of libccd. | |
7 | * | |
8 | * Distributed under the OSI-approved BSD License (the "License"); | |
9 | * see accompanying file BDS-LICENSE for details or see | |
10 | * <http://www.opensource.org/licenses/bsd-license.php>. | |
11 | * | |
12 | * This software is distributed WITHOUT ANY WARRANTY; without even the | |
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
14 | * See the License for more information. | |
15 | */ | |
16 | ||
17 | #include <stdio.h> | |
18 | #include <ccd/vec3.h> | |
19 | #include <ccd/dbg.h> | |
20 | ||
21 | static CCD_VEC3(__ccd_vec3_origin, CCD_ZERO, CCD_ZERO, CCD_ZERO); | |
22 | ccd_vec3_t *ccd_vec3_origin = &__ccd_vec3_origin; | |
23 | ||
24 | static ccd_vec3_t points_on_sphere[] = { | |
25 | CCD_VEC3_STATIC(CCD_REAL( 0.000000), CCD_REAL(-0.000000), CCD_REAL(-1.000000)), | |
26 | CCD_VEC3_STATIC(CCD_REAL( 0.723608), CCD_REAL(-0.525725), CCD_REAL(-0.447219)), | |
27 | CCD_VEC3_STATIC(CCD_REAL(-0.276388), CCD_REAL(-0.850649), CCD_REAL(-0.447219)), | |
28 | CCD_VEC3_STATIC(CCD_REAL(-0.894426), CCD_REAL(-0.000000), CCD_REAL(-0.447216)), | |
29 | CCD_VEC3_STATIC(CCD_REAL(-0.276388), CCD_REAL( 0.850649), CCD_REAL(-0.447220)), | |
30 | CCD_VEC3_STATIC(CCD_REAL( 0.723608), CCD_REAL( 0.525725), CCD_REAL(-0.447219)), | |
31 | CCD_VEC3_STATIC(CCD_REAL( 0.276388), CCD_REAL(-0.850649), CCD_REAL( 0.447220)), | |
32 | CCD_VEC3_STATIC(CCD_REAL(-0.723608), CCD_REAL(-0.525725), CCD_REAL( 0.447219)), | |
33 | CCD_VEC3_STATIC(CCD_REAL(-0.723608), CCD_REAL( 0.525725), CCD_REAL( 0.447219)), | |
34 | CCD_VEC3_STATIC(CCD_REAL( 0.276388), CCD_REAL( 0.850649), CCD_REAL( 0.447219)), | |
35 | CCD_VEC3_STATIC(CCD_REAL( 0.894426), CCD_REAL( 0.000000), CCD_REAL( 0.447216)), | |
36 | CCD_VEC3_STATIC(CCD_REAL(-0.000000), CCD_REAL( 0.000000), CCD_REAL( 1.000000)), | |
37 | CCD_VEC3_STATIC(CCD_REAL( 0.425323), CCD_REAL(-0.309011), CCD_REAL(-0.850654)), | |
38 | CCD_VEC3_STATIC(CCD_REAL(-0.162456), CCD_REAL(-0.499995), CCD_REAL(-0.850654)), | |
39 | CCD_VEC3_STATIC(CCD_REAL( 0.262869), CCD_REAL(-0.809012), CCD_REAL(-0.525738)), | |
40 | CCD_VEC3_STATIC(CCD_REAL( 0.425323), CCD_REAL( 0.309011), CCD_REAL(-0.850654)), | |
41 | CCD_VEC3_STATIC(CCD_REAL( 0.850648), CCD_REAL(-0.000000), CCD_REAL(-0.525736)), | |
42 | CCD_VEC3_STATIC(CCD_REAL(-0.525730), CCD_REAL(-0.000000), CCD_REAL(-0.850652)), | |
43 | CCD_VEC3_STATIC(CCD_REAL(-0.688190), CCD_REAL(-0.499997), CCD_REAL(-0.525736)), | |
44 | CCD_VEC3_STATIC(CCD_REAL(-0.162456), CCD_REAL( 0.499995), CCD_REAL(-0.850654)), | |
45 | CCD_VEC3_STATIC(CCD_REAL(-0.688190), CCD_REAL( 0.499997), CCD_REAL(-0.525736)), | |
46 | CCD_VEC3_STATIC(CCD_REAL( 0.262869), CCD_REAL( 0.809012), CCD_REAL(-0.525738)), | |
47 | CCD_VEC3_STATIC(CCD_REAL( 0.951058), CCD_REAL( 0.309013), CCD_REAL( 0.000000)), | |
48 | CCD_VEC3_STATIC(CCD_REAL( 0.951058), CCD_REAL(-0.309013), CCD_REAL( 0.000000)), | |
49 | CCD_VEC3_STATIC(CCD_REAL( 0.587786), CCD_REAL(-0.809017), CCD_REAL( 0.000000)), | |
50 | CCD_VEC3_STATIC(CCD_REAL( 0.000000), CCD_REAL(-1.000000), CCD_REAL( 0.000000)), | |
51 | CCD_VEC3_STATIC(CCD_REAL(-0.587786), CCD_REAL(-0.809017), CCD_REAL( 0.000000)), | |
52 | CCD_VEC3_STATIC(CCD_REAL(-0.951058), CCD_REAL(-0.309013), CCD_REAL(-0.000000)), | |
53 | CCD_VEC3_STATIC(CCD_REAL(-0.951058), CCD_REAL( 0.309013), CCD_REAL(-0.000000)), | |
54 | CCD_VEC3_STATIC(CCD_REAL(-0.587786), CCD_REAL( 0.809017), CCD_REAL(-0.000000)), | |
55 | CCD_VEC3_STATIC(CCD_REAL(-0.000000), CCD_REAL( 1.000000), CCD_REAL(-0.000000)), | |
56 | CCD_VEC3_STATIC(CCD_REAL( 0.587786), CCD_REAL( 0.809017), CCD_REAL(-0.000000)), | |
57 | CCD_VEC3_STATIC(CCD_REAL( 0.688190), CCD_REAL(-0.499997), CCD_REAL( 0.525736)), | |
58 | CCD_VEC3_STATIC(CCD_REAL(-0.262869), CCD_REAL(-0.809012), CCD_REAL( 0.525738)), | |
59 | CCD_VEC3_STATIC(CCD_REAL(-0.850648), CCD_REAL( 0.000000), CCD_REAL( 0.525736)), | |
60 | CCD_VEC3_STATIC(CCD_REAL(-0.262869), CCD_REAL( 0.809012), CCD_REAL( 0.525738)), | |
61 | CCD_VEC3_STATIC(CCD_REAL( 0.688190), CCD_REAL( 0.499997), CCD_REAL( 0.525736)), | |
62 | CCD_VEC3_STATIC(CCD_REAL( 0.525730), CCD_REAL( 0.000000), CCD_REAL( 0.850652)), | |
63 | CCD_VEC3_STATIC(CCD_REAL( 0.162456), CCD_REAL(-0.499995), CCD_REAL( 0.850654)), | |
64 | CCD_VEC3_STATIC(CCD_REAL(-0.425323), CCD_REAL(-0.309011), CCD_REAL( 0.850654)), | |
65 | CCD_VEC3_STATIC(CCD_REAL(-0.425323), CCD_REAL( 0.309011), CCD_REAL( 0.850654)), | |
66 | CCD_VEC3_STATIC(CCD_REAL( 0.162456), CCD_REAL( 0.499995), CCD_REAL( 0.850654)) | |
67 | }; | |
68 | ccd_vec3_t *ccd_points_on_sphere = points_on_sphere; | |
69 | size_t ccd_points_on_sphere_len = sizeof(points_on_sphere) / sizeof(ccd_vec3_t); | |
70 | ||
71 | ||
72 | _ccd_inline ccd_real_t __ccdVec3PointSegmentDist2(const ccd_vec3_t *P, | |
73 | const ccd_vec3_t *x0, | |
74 | const ccd_vec3_t *b, | |
75 | ccd_vec3_t *witness) | |
76 | { | |
77 | // The computation comes from solving equation of segment: | |
78 | // S(t) = x0 + t.d | |
79 | // where - x0 is initial point of segment | |
80 | // - d is direction of segment from x0 (|d| > 0) | |
81 | // - t belongs to <0, 1> interval | |
82 | // | |
83 | // Than, distance from a segment to some point P can be expressed: | |
84 | // D(t) = |x0 + t.d - P|^2 | |
85 | // which is distance from any point on segment. Minimization | |
86 | // of this function brings distance from P to segment. | |
87 | // Minimization of D(t) leads to simple quadratic equation that's | |
88 | // solving is straightforward. | |
89 | // | |
90 | // Bonus of this method is witness point for free. | |
91 | ||
92 | ccd_real_t dist, t; | |
93 | ccd_vec3_t d, a; | |
94 | ||
95 | // direction of segment | |
96 | ccdVec3Sub2(&d, b, x0); | |
97 | ||
98 | // precompute vector from P to x0 | |
99 | ccdVec3Sub2(&a, x0, P); | |
100 | ||
101 | t = -CCD_REAL(1.) * ccdVec3Dot(&a, &d); | |
102 | t /= ccdVec3Len2(&d); | |
103 | ||
104 | if (t < CCD_ZERO || ccdIsZero(t)){ | |
105 | dist = ccdVec3Dist2(x0, P); | |
106 | if (witness) | |
107 | ccdVec3Copy(witness, x0); | |
108 | }else if (t > CCD_ONE || ccdEq(t, CCD_ONE)){ | |
109 | dist = ccdVec3Dist2(b, P); | |
110 | if (witness) | |
111 | ccdVec3Copy(witness, b); | |
112 | }else{ | |
113 | if (witness){ | |
114 | ccdVec3Copy(witness, &d); | |
115 | ccdVec3Scale(witness, t); | |
116 | ccdVec3Add(witness, x0); | |
117 | dist = ccdVec3Dist2(witness, P); | |
118 | }else{ | |
119 | // recycling variables | |
120 | ccdVec3Scale(&d, t); | |
121 | ccdVec3Add(&d, &a); | |
122 | dist = ccdVec3Len2(&d); | |
123 | } | |
124 | } | |
125 | ||
126 | return dist; | |
127 | } | |
128 | ||
129 | ccd_real_t ccdVec3PointSegmentDist2(const ccd_vec3_t *P, | |
130 | const ccd_vec3_t *x0, const ccd_vec3_t *b, | |
131 | ccd_vec3_t *witness) | |
132 | { | |
133 | return __ccdVec3PointSegmentDist2(P, x0, b, witness); | |
134 | } | |
135 | ||
136 | ccd_real_t ccdVec3PointTriDist2(const ccd_vec3_t *P, | |
137 | const ccd_vec3_t *x0, const ccd_vec3_t *B, | |
138 | const ccd_vec3_t *C, | |
139 | ccd_vec3_t *witness) | |
140 | { | |
141 | // Computation comes from analytic expression for triangle (x0, B, C) | |
142 | // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and | |
143 | // Then equation for distance is: | |
144 | // D(s, t) = | T(s, t) - P |^2 | |
145 | // This leads to minimization of quadratic function of two variables. | |
146 | // The solution from is taken only if s is between 0 and 1, t is | |
147 | // between 0 and 1 and t + s < 1, otherwise distance from segment is | |
148 | // computed. | |
149 | ||
150 | ccd_vec3_t d1, d2, a; | |
151 | ccd_real_t u, v, w, p, q, r; | |
152 | ccd_real_t s, t, dist, dist2; | |
153 | ccd_vec3_t witness2; | |
154 | ||
155 | ccdVec3Sub2(&d1, B, x0); | |
156 | ccdVec3Sub2(&d2, C, x0); | |
157 | ccdVec3Sub2(&a, x0, P); | |
158 | ||
159 | u = ccdVec3Dot(&a, &a); | |
160 | v = ccdVec3Dot(&d1, &d1); | |
161 | w = ccdVec3Dot(&d2, &d2); | |
162 | p = ccdVec3Dot(&a, &d1); | |
163 | q = ccdVec3Dot(&a, &d2); | |
164 | r = ccdVec3Dot(&d1, &d2); | |
165 | ||
166 | s = (q * r - w * p) / (w * v - r * r); | |
167 | t = (-s * r - q) / w; | |
168 | ||
169 | if ((ccdIsZero(s) || s > CCD_ZERO) | |
170 | && (ccdEq(s, CCD_ONE) || s < CCD_ONE) | |
171 | && (ccdIsZero(t) || t > CCD_ZERO) | |
172 | && (ccdEq(t, CCD_ONE) || t < CCD_ONE) | |
173 | && (ccdEq(t + s, CCD_ONE) || t + s < CCD_ONE)){ | |
174 | ||
175 | if (witness){ | |
176 | ccdVec3Scale(&d1, s); | |
177 | ccdVec3Scale(&d2, t); | |
178 | ccdVec3Copy(witness, x0); | |
179 | ccdVec3Add(witness, &d1); | |
180 | ccdVec3Add(witness, &d2); | |
181 | ||
182 | dist = ccdVec3Dist2(witness, P); | |
183 | }else{ | |
184 | dist = s * s * v; | |
185 | dist += t * t * w; | |
186 | dist += CCD_REAL(2.) * s * t * r; | |
187 | dist += CCD_REAL(2.) * s * p; | |
188 | dist += CCD_REAL(2.) * t * q; | |
189 | dist += u; | |
190 | } | |
191 | }else{ | |
192 | dist = __ccdVec3PointSegmentDist2(P, x0, B, witness); | |
193 | ||
194 | dist2 = __ccdVec3PointSegmentDist2(P, x0, C, &witness2); | |
195 | if (dist2 < dist){ | |
196 | dist = dist2; | |
197 | if (witness) | |
198 | ccdVec3Copy(witness, &witness2); | |
199 | } | |
200 | ||
201 | dist2 = __ccdVec3PointSegmentDist2(P, B, C, &witness2); | |
202 | if (dist2 < dist){ | |
203 | dist = dist2; | |
204 | if (witness) | |
205 | ccdVec3Copy(witness, &witness2); | |
206 | } | |
207 | } | |
208 | ||
209 | return dist; | |
210 | } |