Codebase list libccd / 487c1b6
Imported Upstream version 1.5 Jose Luis Rivero 10 years ago
97 changed file(s) with 10617 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
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 SUBDIRS = src
1
2 EXTRA_DIST = doc \
3 BSD-LICENSE \
4 README \
5 make-release.sh
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 #!/bin/sh
1
2 libtoolize -f -c
3 aclocal
4 autoheader -f
5 autoconf
6 automake -a --foreign -f -c
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."
(New empty file)
(New empty file)
(New empty file)
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 Reference
1 ==========
2
3 .. literalinclude:: ../src/ccd/ccd.h
4 :language: c
5 :linenos:
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 *.o
1 *.a
2 ccd/config.h
3 ccd/config.h.in
4
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, &center->v1);
155 ccd->center2(obj2, &center->v2);
156 ccdVec3Sub2(&center->v, &center->v1, &center->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 regressions/tmp.*
1 bench-out/*
2 *.o
3 test
4 bench
5 bench2
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
(New empty file)
0 *~
1 *.o
2 *.a
3 tmp.*
4 test
5
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
1
2
3 ---- boxboxSeparate ----
4
5
6
7
8
9 ---- boxboxPenetration ----
10
11
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
1
2
3 ---- cylcylPenetration ----
4
5
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
1
2
3 ---- boxboxSeparate ----
4
5
6
7
8
9 ---- boxboxPenetration ----
10
11
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
1
2
3 ---- mprCylcylPenetration ----
4
5
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 }