Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5403a286d | ||
|
|
4198b5d007 | ||
|
|
827c71210e | ||
|
|
24a06afaf6 | ||
|
|
3536c92db7 | ||
|
|
25bcf35115 | ||
|
|
4cbc21b73a | ||
|
|
abe3f08bb6 | ||
|
|
a20b076073 | ||
|
|
a3064251ee |
@@ -13,6 +13,10 @@ changes made. See document footer for additional details.
|
||||
--- 2020-xx-xx Release 7.32.2 ---
|
||||
----------------------------------------------------------------------
|
||||
|
||||
* added subtract subcommand to MGED analyze command - Cliff Yapp
|
||||
* added intersect subcommand to MGED analyze command - Cliff Yapp
|
||||
* added summarize subcommand to MGED analyze command - Cliff Yapp
|
||||
* added quiet (-q) flag to MGED kill command - Cliff Yapp
|
||||
* added MGED stat command for reporting of object info - Cliff Yapp
|
||||
* corrected examples in gdiff man page - Cliff Yapp
|
||||
* fixed help message for -F option on gdiff command - Cliff Yapp
|
||||
|
||||
@@ -36,6 +36,7 @@ include(${BRLCAD_SOURCE_DIR}/misc/CMake/DocBook.cmake)
|
||||
|
||||
add_subdirectory(articles)
|
||||
add_subdirectory(books)
|
||||
add_subdirectory(devguides)
|
||||
add_subdirectory(lessons)
|
||||
add_subdirectory(presentations)
|
||||
add_subdirectory(specifications)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# Style sheet for XSLT transformation to HTML pages
|
||||
if(BRLCAD_EXTRADOCS_HTML)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../resources/brlcad/brlcad-man-xhtml-stylesheet.xsl.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../resources/brlcad/brlcad-man-xhtml-stylesheet.xsl)
|
||||
endif(BRLCAD_EXTRADOCS_HTML)
|
||||
|
||||
if(BRLCAD_EXTRADOCS_PHP)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../resources/brlcad/brlcad-man-xhtml-stylesheet.xsl.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../resources/brlcad/brlcad-man-xhtml-stylesheet.xsl)
|
||||
endif(BRLCAD_EXTRADOCS_PHP)
|
||||
|
||||
# Style sheet for XSLT transformation to manual pages
|
||||
if(BRLCAD_EXTRADOCS_MAN)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../resources/brlcad/brlcad-man-stylesheet.xsl.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../resources/brlcad/brlcad-man-stylesheet.xsl)
|
||||
endif(BRLCAD_EXTRADOCS_MAN)
|
||||
|
||||
# Files for PDF
|
||||
if(BRLCAD_EXTRADOCS_PDF)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../resources/brlcad/brlcad-man-fo-stylesheet.xsl.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../resources/brlcad/brlcad-man-fo-stylesheet.xsl)
|
||||
endif(BRLCAD_EXTRADOCS_PDF)
|
||||
|
||||
# For HTML, MAN and FO (FO is an intermediate file used in the
|
||||
# XML->PDF transformation) we use variables to hold the full
|
||||
# stylesheet path. In the case we need to further
|
||||
# customize FO stylesheets we can have separate CMake logic in
|
||||
# appropriate directories to handle the customization (e.g., the
|
||||
# BRL-CAD manuals in books/en/CMakeLists.txt).
|
||||
set(XSL_PHP_STYLESHEET "${CMAKE_CURRENT_BINARY_DIR}/../resources/brlcad/wordpress.xsl")
|
||||
set(XSL_HTML_STYLESHEET "${CMAKE_CURRENT_BINARY_DIR}/../resources/brlcad/brlcad-man-xhtml-stylesheet.xsl")
|
||||
set(XSL_MAN_STYLESHEET "${CMAKE_CURRENT_BINARY_DIR}/../resources/brlcad/brlcad-man-stylesheet.xsl")
|
||||
set(XSL_FO_STYLESHEET "${CMAKE_CURRENT_BINARY_DIR}/../resources/brlcad/brlcad-man-fo-stylesheet.xsl")
|
||||
|
||||
set(devguides_EN
|
||||
bool_eval_development.xml
|
||||
)
|
||||
|
||||
set(devguides_EN_IMAGES
|
||||
images/ccx_overlap_event.png
|
||||
images/ssx_transverse_event.png
|
||||
images/ssx_tangent_event.png
|
||||
images/compare_endpoint_style.png
|
||||
images/lcurves_with_shaded_context.png
|
||||
images/ssx_10_vs_13.png
|
||||
images/curve_traversal_directions.png
|
||||
images/axis_X.png
|
||||
images/intermediate_linked_curves.png
|
||||
images/ssx_overlap_event.png
|
||||
images/evaluation_overview.png
|
||||
)
|
||||
|
||||
ADD_DOC(devguides_EN html/devguides)
|
||||
ADD_DOC(devguides_EN_IMAGES html/devguides/images)
|
||||
ADD_DOCBOOK("HTML;PHP;PDF" devguides_EN devguides/en devguides_EN_IMAGES_cp)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width: 8
|
||||
# mode: cmake
|
||||
# indent-tabs-mode: t
|
||||
# End:
|
||||
# ex: shiftwidth=2 tabstop=8
|
||||
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 646 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
@@ -10,9 +10,7 @@
|
||||
<refnamediv xml:id="name">
|
||||
<refname>analyze</refname>
|
||||
<refpurpose>
|
||||
Displays the rotation and fallback angles, surface area, and
|
||||
plane equation for each face of the ARB specified on the command line. The total
|
||||
surface area, volume, and the length of each edge are also displayed.
|
||||
Report and/or compute analytical information about the listed objects.
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
@@ -20,39 +18,243 @@
|
||||
<refsynopsisdiv xml:id="synopsis">
|
||||
<cmdsynopsis sepchar=" ">
|
||||
<command>analyze</command>
|
||||
<arg choice="req" rep="norepeat"><replaceable>arb_name</replaceable></arg>
|
||||
<arg choice="opt" rep="repeat"><replaceable>options</replaceable></arg>
|
||||
<arg choice="opt" rep="norepeat"><replaceable>subcommand</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term></term><listitem>
|
||||
<cmdsynopsis sepchar=" ">
|
||||
<command>summarize</command>
|
||||
<arg choice="req" rep="repeat">obj</arg>
|
||||
</cmdsynopsis>
|
||||
</listitem></varlistentry>
|
||||
|
||||
<varlistentry><term></term><listitem>
|
||||
<cmdsynopsis sepchar=" ">
|
||||
<command>intersect</command>
|
||||
<arg choice="opt" rep="repeat"><replaceable>options</replaceable></arg>
|
||||
<arg choice="req" rep="repeat">obj1 obj2 [...]</arg>
|
||||
</cmdsynopsis>
|
||||
</listitem></varlistentry>
|
||||
|
||||
<varlistentry><term></term><listitem>
|
||||
<cmdsynopsis sepchar=" ">
|
||||
<command>subtract</command>
|
||||
<arg choice="opt" rep="repeat"><replaceable>options</replaceable></arg>
|
||||
<arg choice="req" rep="repeat">obj1 obj2 [...]</arg>
|
||||
</cmdsynopsis>
|
||||
</listitem></varlistentry>
|
||||
</variablelist>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsection xml:id="description"><title>DESCRIPTION</title>
|
||||
|
||||
<para>
|
||||
The <command>analyze</command> command displays the rotation and fallback
|
||||
angles, surface area, and plane equation for each face of the ARB specified
|
||||
on the command line. The total surface area, volume, and the length of each
|
||||
edge are also displayed. If executed while editing an ARB, the arb_name may
|
||||
be omitted, and the ARB being edited will be analyzed.
|
||||
The <command>analyze</command> command provides an array of reporting and
|
||||
shape generation capabilities. The classic behavior (and the behavior users
|
||||
will see if calling without specifying a subcommand) is a report summarizing
|
||||
geometric information about the specified solid(s). This behavior may also
|
||||
be explicitly invoked by the <command>summarize</command> subcommand.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <command>intersect</command> will take the first object specified and
|
||||
intersect it with any subsequently specified objects - in effect, building
|
||||
up a new object with the geoemtry common to all objects specified.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <command>subtract</command> will take the first object specified and
|
||||
subtract from it any subsequently specified objects.
|
||||
</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection xml:id="examples"><title>EXAMPLES</title>
|
||||
|
||||
<para>
|
||||
The example shows how to display information about an ARB's rotation and
|
||||
fallback angles, surface area, and plane equation for its face.
|
||||
Edge information is also displayed.
|
||||
</para>
|
||||
<example><title>Analyze a particular <emphasis>ARB</emphasis></title>
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>analyze box.s</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
box.s: ARB8
|
||||
1 (30.0283, -5.21153, -16.3791)
|
||||
2 (30.0283, 21.5812, -16.3791)
|
||||
3 (30.0283, 21.5812, 10.4137)
|
||||
4 (30.0283, -5.21153, 10.4137)
|
||||
5 (3.23558, -5.21153, -16.3791)
|
||||
6 (3.23558, 21.5812, -16.3791)
|
||||
7 (3.23558, 21.5812, 10.4137)
|
||||
8 (3.23558, -5.21153, 10.4137)
|
||||
|
||||
+------+---------------------------+-------------------------------------------------+--------------+
|
||||
| FACE | ROT FB | PLANE EQUATION | SURFACE AREA |
|
||||
+------+---------------------------+-------------------------------------------------+--------------+
|
||||
| 1234 | 0.00000000 0.00000000 | 1.00000000 0.00000000 0.00000000 30.02833557 | 717.85172729 |
|
||||
| 5678 | 180.00000000 -0.00000000 | -1.00000000 -0.00000000 -0.00000000 -3.23558044 | 717.85172729 |
|
||||
| 1584 | 270.00000000 -0.00000000 | -0.00000000 -1.00000000 -0.00000000 5.21152973 | 717.85172729 |
|
||||
| 2376 | 90.00000000 -0.00000000 | -0.00000000 1.00000000 -0.00000000 21.58122540 | 717.85172729 |
|
||||
| 1265 | 0.00000000 -90.00000000 | -0.00000000 0.00000000 -1.00000000 16.37908936 | 717.85172729 |
|
||||
| 4378 | 0.00000000 90.00000000 | 0.00000000 -0.00000000 1.00000000 10.41366577 | 717.85172729 |
|
||||
+------+---------------------------+-------------------------------------------------+--------------+
|
||||
|
||||
+--------------------+--------------------+--------------------+--------------------+
|
||||
| EDGE LENGTH | EDGE LENGTH | EDGE LENGTH | EDGE LENGTH |
|
||||
+--------------------+--------------------+--------------------+--------------------+
|
||||
| 12 26.79275513 | 23 26.79275513 | 34 26.79275513 | 14 26.79275513 |
|
||||
| 15 26.79275513 | 56 26.79275513 | 26 26.79275513 | 67 26.79275513 |
|
||||
| 78 26.79275513 | 58 26.79275513 | 48 26.79275513 | 37 26.79275513 |
|
||||
+--------------------+--------------------+--------------------+--------------------+
|
||||
|
||||
+-------------------------------+
|
||||
| Volume = 19233.22554681 |
|
||||
| Surface Area = 4307.11036376 |
|
||||
| Gallons = 0.00508088 |
|
||||
+-------------------------------+
|
||||
</literallayout>
|
||||
</example>
|
||||
|
||||
<example><title>Analyze a particular <emphasis>TOR</emphasis></title>
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>analyze tor</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
tor: torus (TOR)
|
||||
V (4.91624, -32.8022, 31.7118), r1=25.4 (A), r2=5.08 (H)
|
||||
N=(0, 1, 0)
|
||||
A=(0, -0, 1)
|
||||
B=(1, 0, -0)
|
||||
vector to inner edge = (0, -0, 20.32)
|
||||
vector to outer edge = (0, -0, 30.48)
|
||||
|
||||
Centroid: (4.91624, -32.8022, 31.7118)
|
||||
|
||||
+-------------------------------+
|
||||
| Volume = 12938.70529707 |
|
||||
| Surface Area = 5093.97853992 |
|
||||
| Gallons = 0.00341804 |
|
||||
+-------------------------------+
|
||||
</literallayout>
|
||||
</example>
|
||||
|
||||
<example><title>Points inside a sphere</title>
|
||||
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>l sph.s</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
sph.s: ellipsoid (ELL)
|
||||
V (0, 0, 0)
|
||||
A (10, 0, 0) mag=10
|
||||
B (0, 10, 0) mag=10
|
||||
C (0, 0, 10) mag=10
|
||||
A direction cosines=(0, 90, 90)
|
||||
A rotation angle=0, fallback angle=0
|
||||
B direction cosines=(90, 0, 90)
|
||||
B rotation angle=90, fallback angle=0
|
||||
C direction cosines=(90, 90, 0)
|
||||
C rotation angle=0, fallback angle=90
|
||||
</literallayout>
|
||||
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>l pnts.s</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
pnts.s: Point Cloud (PNTS)
|
||||
Total number of points: 6
|
||||
Default scale: 0.000000
|
||||
point#, (point)
|
||||
1, (2.000000 2.000000 2.000000)
|
||||
2, (0.000000 0.000000 -5.000000)
|
||||
3, (0.000000 0.000000 10.000000)
|
||||
4, (0.000000 0.000000 20.000000)
|
||||
5, (10.000000 0.000000 10.000000)
|
||||
6, (0.000000 10.000000 20.000000)
|
||||
</literallayout>
|
||||
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>analyze intersect -o inside.s pnts.s sph.s</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
3
|
||||
</literallayout>
|
||||
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>l inside.s</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
inside.s: Point Cloud (PNTS)
|
||||
Total number of points: 3
|
||||
Default scale: 0.000000
|
||||
point#, (point)
|
||||
1, (0.000000 0.000000 10.000000)
|
||||
2, (0.000000 0.000000 -5.000000)
|
||||
3, (2.000000 2.000000 2.000000)
|
||||
</literallayout>
|
||||
|
||||
</example>
|
||||
|
||||
|
||||
<example><title>Points outside a sphere</title>
|
||||
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>l sph.s</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
sph.s: ellipsoid (ELL)
|
||||
V (0, 0, 0)
|
||||
A (10, 0, 0) mag=10
|
||||
B (0, 10, 0) mag=10
|
||||
C (0, 0, 10) mag=10
|
||||
A direction cosines=(0, 90, 90)
|
||||
A rotation angle=0, fallback angle=0
|
||||
B direction cosines=(90, 0, 90)
|
||||
B rotation angle=90, fallback angle=0
|
||||
C direction cosines=(90, 90, 0)
|
||||
C rotation angle=0, fallback angle=90
|
||||
</literallayout>
|
||||
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>l pnts.s</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
pnts.s: Point Cloud (PNTS)
|
||||
Total number of points: 6
|
||||
Default scale: 0.000000
|
||||
point#, (point)
|
||||
1, (2.000000 2.000000 2.000000)
|
||||
2, (0.000000 0.000000 -5.000000)
|
||||
3, (0.000000 0.000000 10.000000)
|
||||
4, (0.000000 0.000000 20.000000)
|
||||
5, (10.000000 0.000000 10.000000)
|
||||
6, (0.000000 10.000000 20.000000)
|
||||
</literallayout>
|
||||
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>analyze subtract -o outside.s pnts.s sph</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
3
|
||||
</literallayout>
|
||||
|
||||
<para>
|
||||
<prompt>mged></prompt> <userinput>analyze arb_name</userinput>
|
||||
</para>
|
||||
<para>
|
||||
Rotation and fallback angles, surface area, and plane equation for
|
||||
each face of the ARB specified on the command line are displayed along
|
||||
with edge information.
|
||||
<prompt>mged></prompt> <userinput>l outside.s</userinput>
|
||||
</para>
|
||||
<literallayout>
|
||||
outside.s: Point Cloud (PNTS)
|
||||
Total number of points: 3
|
||||
Default scale: 0.000000
|
||||
point#, (point)
|
||||
1, (0.000000 10.000000 20.000000)
|
||||
2, (10.000000 0.000000 10.000000)
|
||||
3, (0.000000 0.000000 20.000000)
|
||||
</literallayout>
|
||||
|
||||
|
||||
</example>
|
||||
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection xml:id="author"><title>AUTHOR</title>
|
||||
|
||||
@@ -1,61 +1,79 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="kill">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>KILL</refentrytitle>
|
||||
<manvolnum>nged</manvolnum>
|
||||
<refmiscinfo class="source">BRL-CAD</refmiscinfo>
|
||||
<refmiscinfo class="manual">BRL-CAD User Commands</refmiscinfo>
|
||||
</refmeta>
|
||||
<refmeta>
|
||||
<refentrytitle>KILL</refentrytitle>
|
||||
<manvolnum>nged</manvolnum>
|
||||
<refmiscinfo class="source">BRL-CAD</refmiscinfo>
|
||||
<refmiscinfo class="manual">BRL-CAD User Commands</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv xml:id="name">
|
||||
<refname>kill</refname>
|
||||
<refpurpose>Deletes specified <emphasis>objects</emphasis> from the current database.
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
<refnamediv xml:id="name">
|
||||
<refname>kill</refname>
|
||||
<refpurpose>Deletes specified <emphasis>objects</emphasis> from the current database.
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<!-- body begins here -->
|
||||
<refsynopsisdiv xml:id="synopsis">
|
||||
<cmdsynopsis sepchar=" ">
|
||||
<command>kill</command>
|
||||
<arg choice="opt" rep="norepeat">-f</arg>
|
||||
<arg choice="req" rep="norepeat"><replaceable>objects</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
<!-- body begins here -->
|
||||
<refsynopsisdiv xml:id="synopsis">
|
||||
<cmdsynopsis sepchar=" ">
|
||||
<command>kill</command>
|
||||
<arg choice="opt" rep="norepeat">-f</arg>
|
||||
<arg choice="req" rep="norepeat"><replaceable>objects</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsection xml:id="description"><title>DESCRIPTION</title>
|
||||
<refsection xml:id="description"><title>DESCRIPTION</title>
|
||||
|
||||
<para>
|
||||
Deletes the specified <emphasis>objects</emphasis> from the current database.
|
||||
This command affects only the <emphasis>objects</emphasis> actually listed on the command line. If a combination is killed, its members are not affected. If the <emphasis>-f </emphasis>option is specified, then kill will not complain if some, or all, of the <emphasis>objects</emphasis> specified do not actually exist in the database. Note that the <emphasis>objects</emphasis> are killed immediately. There is no need for a <command> write file</command> command in MGED, and there is no <command>undo</command> command. <emphasis remap="B" role="bold">Use this command with caution.</emphasis> Other commands that remove objects from the database are <command>killall</command> and <command>killtree </command>.
|
||||
Deletes the specified <emphasis>objects</emphasis> from the current database. This command
|
||||
affects only the <emphasis>objects</emphasis> actually listed on the command line. If a
|
||||
combination is killed, its members are not affected. If the <emphasis>-f</emphasis>option
|
||||
is specified, then kill will not complain if some, or all, of the <emphasis>objects</emphasis>
|
||||
specified do not actually exist in the database. Note that the <emphasis>objects</emphasis>
|
||||
are killed immediately. There is no need for a <command>write file</command> command in MGED,
|
||||
and there is no <command>undo</command> command. <emphasis remap="B" role="bold">Use this
|
||||
command with caution.</emphasis> Other commands that remove objects from the database are
|
||||
<command>killall</command> and <command>killtree</command>.
|
||||
</para>
|
||||
</refsection>
|
||||
<para>
|
||||
The <option>-q</option> option may be added to suppress database object lookup messages
|
||||
reporting failure, which will otherwise let the user know an invalid object was specified.
|
||||
</para>
|
||||
</refsection>
|
||||
|
||||
<refsection xml:id="examples"><title>EXAMPLES</title>
|
||||
|
||||
<para>The example shows the use of the <command>kill</command> command to delete specified objects from the database.
|
||||
<refsection xml:id="examples"><title>EXAMPLES</title>
|
||||
<para>
|
||||
The example shows the use of the <command>kill</command> command to delete specified objects
|
||||
from the database.
|
||||
</para>
|
||||
<example><title>Delete objects from the database.</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><prompt>mged></prompt> <userinput>kill group1 region2 shapeb</userinput></term>
|
||||
<listitem>
|
||||
<para>Deletes <emphasis>group1, region2</emphasis>, and <emphasis>shapeb</emphasis> from the database.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><prompt>mged></prompt> <userinput>kill group1 region2 shapeb</userinput></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Deletes <emphasis>group1, region2</emphasis>, and <emphasis>shapeb</emphasis> from
|
||||
the database.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</example>
|
||||
|
||||
</refsection>
|
||||
</refsection>
|
||||
|
||||
<refsection xml:id="author"><title>AUTHOR</title><para>BRL-CAD Team</para></refsection>
|
||||
<refsection xml:id="author"><title>AUTHOR</title>
|
||||
<para>
|
||||
BRL-CAD Team
|
||||
</para>
|
||||
</refsection>
|
||||
|
||||
<refsection xml:id="bug_reports"><title>BUG REPORTS</title>
|
||||
<refsection xml:id="bug_reports"><title>BUG REPORTS</title>
|
||||
|
||||
<para>
|
||||
Reports of bugs or problems should be submitted via electronic
|
||||
mail to <email>devs@brlcad.org</email>
|
||||
</para>
|
||||
</refsection>
|
||||
</refsection>
|
||||
</refentry>
|
||||
|
||||
@@ -860,6 +860,11 @@ GED_EXPORT int ged_pnts(struct ged *gedp, int argc, const char *argv[]);
|
||||
*/
|
||||
GED_EXPORT extern int ged_stat(struct ged *gedp, int argc, const char *argv[]);
|
||||
|
||||
|
||||
|
||||
/* Debugging command for brep plotting */
|
||||
GED_EXPORT extern int ged_dplot(struct ged *gedp, int argc, const char *argv[]);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ set(LIBBREP_SOURCES
|
||||
cdt/mesh.cpp
|
||||
cdt/ovlps_simple.cpp
|
||||
cdt/tri_isect.cpp
|
||||
debug_plot.cpp
|
||||
intersect.cpp
|
||||
tools/tools.cpp
|
||||
opennurbs_ext.cpp
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
*
|
||||
* Evaluate NURBS booleans (union, intersection and difference).
|
||||
*
|
||||
* Additional documentation can be found in the "NURBS Boolean Evaluation
|
||||
* Development Guide" docbook article (bool_eval_development.html).
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
@@ -31,6 +33,7 @@
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
||||
#include "bio.h"
|
||||
|
||||
@@ -43,20 +46,15 @@
|
||||
#include "brep/ray.h"
|
||||
#include "brep/util.h"
|
||||
|
||||
#include "debug_plot.h"
|
||||
#include "brep_except.h"
|
||||
#include "brep_defines.h"
|
||||
|
||||
DebugPlot *dplot = NULL;
|
||||
|
||||
// Whether to output the debug messages about b-rep booleans.
|
||||
#define DEBUG_BREP_BOOLEAN 0
|
||||
|
||||
// tol value used in ON_Intersect()s. We use a smaller tolerance than the
|
||||
// default one 0.001.
|
||||
#define INTERSECTION_TOL 1e-4
|
||||
|
||||
// tol value used in ON_3dVector::IsParallelTo(). We use a smaller tolerance
|
||||
// than the default one ON_PI/180.
|
||||
#define ANGLE_TOL ON_PI/1800.0
|
||||
|
||||
|
||||
struct IntersectPoint {
|
||||
ON_3dPoint m_pt; // 3D intersection point
|
||||
@@ -104,7 +102,7 @@ struct SSICurve {
|
||||
};
|
||||
|
||||
|
||||
HIDDEN void
|
||||
void
|
||||
append_to_polycurve(ON_Curve *curve, ON_PolyCurve &polycurve);
|
||||
// We link the SSICurves that share an endpoint, and form this new structure,
|
||||
// which has many similar behaviors as ON_Curve, e.g. PointAt(), Reverse().
|
||||
@@ -344,7 +342,7 @@ curve_t_compare(const IntersectPoint *p1, const IntersectPoint *p2)
|
||||
}
|
||||
|
||||
|
||||
HIDDEN void
|
||||
void
|
||||
append_to_polycurve(ON_Curve *curve, ON_PolyCurve &polycurve)
|
||||
{
|
||||
// use this function rather than ON_PolyCurve::Append() to avoid
|
||||
@@ -3445,7 +3443,7 @@ get_face_intersection_curves(
|
||||
std::set<int> *unused = i < face_count1 ? &unused1 : &unused2;
|
||||
std::set<int> *intact = i < face_count1 ? &finalform1 : &finalform2;
|
||||
int curr_index = i < face_count1 ? i : i - face_count1;
|
||||
if (face.BoundingBox().MinimumDistanceTo(brep->BoundingBox()) > ON_ZERO_TOLERANCE) {
|
||||
if (face.BoundingBox().MinimumDistanceTo(brep->BoundingBox()) > INTERSECTION_TOL) {
|
||||
switch (operation) {
|
||||
case BOOLEAN_UNION:
|
||||
intact->insert(curr_index);
|
||||
@@ -3483,8 +3481,8 @@ get_face_intersection_curves(
|
||||
if (unused2.find(j) == unused2.end() && finalform2.find(j) == finalform2.end()) {
|
||||
// If the two faces don't interact according to their bounding boxes,
|
||||
// they won't be a source of events - otherwise, they must be checked.
|
||||
fastf_t disjoint = brep1->m_F[i].BoundingBox().MinimumDistanceTo(brep2->m_F[j].BoundingBox());
|
||||
if (!(disjoint > ON_ZERO_TOLERANCE)) {
|
||||
fastf_t face_dist = brep1->m_F[i].BoundingBox().MinimumDistanceTo(brep2->m_F[j].BoundingBox());
|
||||
if (face_dist <= INTERSECTION_TOL) {
|
||||
intersection_candidates.insert(std::pair<int, int>(i, j));
|
||||
}
|
||||
}
|
||||
@@ -3563,6 +3561,10 @@ get_face_intersection_curves(
|
||||
if (results <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dplot->SSX(events, brep1, brep1->m_F[i].m_si, brep2, brep2->m_F[j].m_si);
|
||||
dplot->WriteLog();
|
||||
|
||||
ON_SimpleArray<ON_Curve *> face1_curves, face2_curves;
|
||||
for (int k = 0; k < events.Count(); k++) {
|
||||
if (events[k].m_type == ON_SSX_EVENT::ssx_tangent ||
|
||||
@@ -3590,6 +3592,8 @@ get_face_intersection_curves(
|
||||
}
|
||||
}
|
||||
}
|
||||
dplot->ClippedFaceCurves(surf1, surf2, face1_curves, face2_curves);
|
||||
dplot->WriteLog();
|
||||
|
||||
if (DEBUG_BREP_BOOLEAN) {
|
||||
// Look for coplanar faces
|
||||
@@ -3603,7 +3607,6 @@ get_face_intersection_curves(
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3694,6 +3697,7 @@ categorize_trimmed_faces(
|
||||
}
|
||||
|
||||
splitted[j]->m_rev = false;
|
||||
splitted[j]->m_belong_to_final = TrimmedFace::NOT_BELONG;
|
||||
switch (face_location) {
|
||||
case INSIDE_BREP:
|
||||
if (operation == BOOLEAN_INTERSECT ||
|
||||
@@ -3798,6 +3802,8 @@ get_evaluated_faces(const ON_Brep *brep1, const ON_Brep *brep2, op_type operatio
|
||||
for (int i = 0; i < original_faces.Count(); i++) {
|
||||
TrimmedFace *first = original_faces[i];
|
||||
ON_ClassArray<LinkedCurve> linked_curves = link_curves(curves_array[i]);
|
||||
dplot->LinkedCurves(first->m_face->SurfaceOf(), linked_curves);
|
||||
dplot->WriteLog();
|
||||
|
||||
ON_SimpleArray<TrimmedFace *> splitted = split_trimmed_face(first, linked_curves);
|
||||
trimmed_faces.Append(splitted);
|
||||
@@ -3826,6 +3832,9 @@ get_evaluated_faces(const ON_Brep *brep1, const ON_Brep *brep2, op_type operatio
|
||||
|
||||
categorize_trimmed_faces(trimmed_faces, brep1, brep2, surf_tree1, surf_tree2, operation);
|
||||
|
||||
dplot->SplitFaces(trimmed_faces);
|
||||
dplot->WriteLog();
|
||||
|
||||
for (int i = 0; i < surf_tree1.Count(); i++) {
|
||||
delete surf_tree1[i];
|
||||
}
|
||||
@@ -3914,6 +3923,14 @@ standardize_loop_orientations(ON_Brep *brep)
|
||||
int
|
||||
ON_Boolean(ON_Brep *evaluated_brep, const ON_Brep *brep1, const ON_Brep *brep2, op_type operation)
|
||||
{
|
||||
static int calls = 0;
|
||||
++calls;
|
||||
std::ostringstream prefix;
|
||||
prefix << "bool" << calls;
|
||||
dplot = new DebugPlot(prefix.str().c_str());
|
||||
dplot->Surfaces(brep1, brep2);
|
||||
dplot->WriteLog();
|
||||
|
||||
ON_ClassArray<ON_SimpleArray<TrimmedFace *> > trimmed_faces;
|
||||
try {
|
||||
/* Deal with the trivial cases up front */
|
||||
@@ -3934,14 +3951,17 @@ ON_Boolean(ON_Brep *evaluated_brep, const ON_Brep *brep1, const ON_Brep *brep2,
|
||||
}
|
||||
evaluated_brep->ShrinkSurfaces();
|
||||
evaluated_brep->Compact();
|
||||
dplot->WriteLog();
|
||||
return 0;
|
||||
}
|
||||
trimmed_faces = get_evaluated_faces(brep1, brep2, operation);
|
||||
} catch (InvalidBooleanOperation &e) {
|
||||
bu_log("%s", e.what());
|
||||
dplot->WriteLog();
|
||||
return -1;
|
||||
} catch (GeometryGenerationError &e) {
|
||||
bu_log("%s", e.what());
|
||||
dplot->WriteLog();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -3999,6 +4019,10 @@ ON_Boolean(ON_Brep *evaluated_brep, const ON_Brep *brep1, const ON_Brep *brep2,
|
||||
bu_log("%s", ON_String(ws).Array());
|
||||
}
|
||||
|
||||
dplot->WriteLog();
|
||||
delete dplot;
|
||||
dplot = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/* B R E P _ D E F I N E S . H
|
||||
* BRL-CAD
|
||||
*
|
||||
* Copyright (c) 2014 United States Government as represented by
|
||||
* the U.S. Army Research Laboratory.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; see the file named COPYING for more
|
||||
* information.
|
||||
*/
|
||||
/** @file brep_defines.h
|
||||
*
|
||||
* Private defines.
|
||||
*
|
||||
*/
|
||||
|
||||
// The maximal depth for subdivision - trade-off between accuracy and
|
||||
// performance.
|
||||
#define NR_MAX_DEPTH 8
|
||||
#define MAX_PCI_DEPTH NR_MAX_DEPTH
|
||||
#define MAX_PSI_DEPTH NR_MAX_DEPTH
|
||||
#define MAX_CCI_DEPTH NR_MAX_DEPTH
|
||||
#define MAX_CSI_DEPTH NR_MAX_DEPTH
|
||||
#define MAX_SSI_DEPTH NR_MAX_DEPTH
|
||||
|
||||
// Used to prevent an infinite loop in the unlikely event that we
|
||||
// can't provide a good starting point for the Newton-Raphson
|
||||
// Iteration.
|
||||
#define NR_MAX_ITERATIONS 100
|
||||
#define PCI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
#define PSI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
#define CCI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
#define CSI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
#define SSI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
|
||||
// We make the default tolerance for PSI the same as that of curve and
|
||||
// surface intersections defined by openNURBS (see opennurbs_curve.h
|
||||
// and opennurbs_surface.h).
|
||||
#define NR_DEFAULT_TOLERANCE 0.001
|
||||
#define PCI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
#define PSI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
#define CCI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
#define CSI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
#define SSI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
|
||||
// tol value used in ON_Intersect()s. We use a smaller tolerance than the
|
||||
// default one 0.001.
|
||||
#define INTERSECTION_TOL 1e-4
|
||||
|
||||
// tol value used in ON_3dVector::IsParallelTo(). We use a smaller tolerance
|
||||
// than the default one ON_PI/180.
|
||||
#define ANGLE_TOL ON_PI/1800.0
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* tab-width: 8
|
||||
* mode: C
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "stroustrup"
|
||||
* End:
|
||||
* ex: shiftwidth=4 tabstop=8
|
||||
*/
|
||||
@@ -0,0 +1,990 @@
|
||||
/* D E B U G _ P L O T . C P P
|
||||
* BRL-CAD
|
||||
*
|
||||
* Copyright (c) 2014 United States Government as represented by
|
||||
* the U.S. Army Research Laboratory.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; see the file named COPYING for more
|
||||
* information.
|
||||
*/
|
||||
/** @file debug_plot.cpp
|
||||
*
|
||||
* DebugPlot implementation. Currently borrows code from librt to
|
||||
* handle the creation of vlists for brep geometry and conversion of
|
||||
* those vlists to unix plot files.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "bu/log.h"
|
||||
#include "bn.h"
|
||||
#include "raytrace.h"
|
||||
#include "vmath.h"
|
||||
#include "debug_plot.h"
|
||||
#include "brep_except.h"
|
||||
|
||||
static unsigned char surface1_color[] = {0, 0, 62};
|
||||
static unsigned char surface2_color[] = {62, 0, 0};
|
||||
static unsigned char surface1_highlight_color[] = {56, 56, 255};
|
||||
static unsigned char surface2_highlight_color[] = {255, 56, 56};
|
||||
|
||||
static unsigned char tangent_color[] = {255, 255, 255};
|
||||
static unsigned char transverse_color[] = {255, 255, 0};
|
||||
static unsigned char overlap_color[] = {0, 255, 0};
|
||||
|
||||
static unsigned char accepted_outerloop_color[] = {0, 255, 0};
|
||||
static unsigned char accepted_innerloop_color[] = {255, 0, 0};
|
||||
static unsigned char unknown_outerloop_color[] = {158, 158, 0};
|
||||
static unsigned char unknown_innerloop_color[] = {158, 158, 0};
|
||||
static unsigned char rejected_outerloop_color[] = {0, 62, 0};
|
||||
static unsigned char rejected_innerloop_color[] = {62, 0, 0};
|
||||
|
||||
DebugPlot::DebugPlot(const char *basename) :
|
||||
prefix(basename),
|
||||
have_surfaces(false),
|
||||
brep1_surf_count(0),
|
||||
brep2_surf_count(0),
|
||||
linked_curve_count(0)
|
||||
{
|
||||
BU_LIST_INIT(&vlist_free_list);
|
||||
}
|
||||
|
||||
DebugPlot::~DebugPlot()
|
||||
{
|
||||
struct bn_vlist *vp;
|
||||
while (BU_LIST_WHILE(vp, bn_vlist, &vlist_free_list)) {
|
||||
BU_LIST_DEQUEUE(&(vp->l));
|
||||
bu_free((char *)vp, "bn_vlist");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
DebugPlot::SurfacePairs(void)
|
||||
{
|
||||
return (int)intersecting_surfaces.size();
|
||||
}
|
||||
|
||||
int
|
||||
DebugPlot::IntersectingIsocurves(int ssx_idx)
|
||||
{
|
||||
int max_isocsx_idx = (int)ssx_isocsx_events.size() - 1;
|
||||
if (ssx_idx < 0 || ssx_idx > max_isocsx_idx) {
|
||||
std::cerr << "DebugPlot::IntersectingIsocurves passed invalid ssx index.\n";
|
||||
return 0;
|
||||
}
|
||||
return (int)ssx_isocsx_events[ssx_idx].size();
|
||||
}
|
||||
|
||||
int
|
||||
DebugPlot::LinkedCurves(void)
|
||||
{
|
||||
return linked_curve_count;
|
||||
}
|
||||
|
||||
HIDDEN void
|
||||
rt_vlist_to_uplot(FILE *fp, const struct bu_list *vhead)
|
||||
{
|
||||
struct bn_vlist *vp;
|
||||
|
||||
for (BU_LIST_FOR(vp, bn_vlist, vhead)) {
|
||||
int i;
|
||||
int nused = vp->nused;
|
||||
const int *cmd = vp->cmd;
|
||||
point_t *pt = vp->pt;
|
||||
|
||||
for (i = 0; i < nused; i++, cmd++, pt++) {
|
||||
switch (*cmd) {
|
||||
case BN_VLIST_POLY_START:
|
||||
case BN_VLIST_TRI_START:
|
||||
break;
|
||||
case BN_VLIST_POLY_MOVE:
|
||||
case BN_VLIST_LINE_MOVE:
|
||||
case BN_VLIST_TRI_MOVE:
|
||||
pdv_3move(fp, *pt);
|
||||
break;
|
||||
case BN_VLIST_POLY_DRAW:
|
||||
case BN_VLIST_POLY_END:
|
||||
case BN_VLIST_LINE_DRAW:
|
||||
case BN_VLIST_TRI_DRAW:
|
||||
case BN_VLIST_TRI_END:
|
||||
pdv_3cont(fp, *pt);
|
||||
break;
|
||||
default:
|
||||
bu_log("rt_vlist_to_uplot: unknown vlist cmd x%x\n",
|
||||
*cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HIDDEN void
|
||||
write_plot_to_file(
|
||||
const char *filename,
|
||||
const struct bu_list *vhead,
|
||||
const unsigned char *color)
|
||||
{
|
||||
FILE *fp = fopen(filename, "w");
|
||||
|
||||
if (!color) {
|
||||
unsigned char clr[] = {255, 0, 0};
|
||||
color = clr;
|
||||
}
|
||||
|
||||
pl_linmod(fp, "solid");
|
||||
pl_color(fp, color[0], color[1], color[2]);
|
||||
rt_vlist_to_uplot(fp, vhead);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void
|
||||
DebugPlot::WriteLog()
|
||||
{
|
||||
std::ostringstream filename;
|
||||
|
||||
// First write out empty plots of different colors, we use this to
|
||||
// "erase" unwanted overlays when running the dplot command.
|
||||
struct bu_list vhead;
|
||||
BU_LIST_INIT(&vhead);
|
||||
point_t origin = {0.0, 0.0, 0.0};
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, origin, BN_VLIST_LINE_MOVE);
|
||||
|
||||
filename << prefix << "_empty0.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, tangent_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty1.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, transverse_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty2.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, overlap_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty3.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, surface1_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty4.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, surface2_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty5.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, surface1_highlight_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty6.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, surface2_highlight_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty7.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, accepted_outerloop_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty8.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, accepted_innerloop_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty9.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, unknown_outerloop_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty10.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, unknown_innerloop_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty11.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, rejected_outerloop_color);
|
||||
filename.str("");
|
||||
filename << prefix << "_empty12.plot3";
|
||||
write_plot_to_file(filename.str().c_str(), &vhead, rejected_innerloop_color);
|
||||
|
||||
// create dplot log file
|
||||
filename.str("");
|
||||
filename << prefix << ".dplot";
|
||||
FILE *fp = fopen(filename.str().c_str(), "w");
|
||||
|
||||
// write out surface-surface intersections
|
||||
fprintf(fp, "surfaces %d %d\n", brep1_surf_count, brep2_surf_count);
|
||||
for (size_t i = 0; i < intersecting_surfaces.size(); ++i) {
|
||||
std::pair<int, int> intersecting = intersecting_surfaces[i];
|
||||
|
||||
int events, b1_isocurves, intersecting_isocurves, b1_clipped, b2_clipped;
|
||||
|
||||
try {
|
||||
events = ssx_events.at(i);
|
||||
} catch (std::out_of_range &e) {
|
||||
events = 0;
|
||||
}
|
||||
try {
|
||||
std::pair<int, int> ccount = ssx_clipped_curves.at(i);
|
||||
b1_clipped = ccount.first;
|
||||
b2_clipped = ccount.second;
|
||||
} catch (std::out_of_range &e) {
|
||||
b1_clipped = b2_clipped = 0;
|
||||
}
|
||||
try {
|
||||
b1_isocurves = ssx_isocsx_brep1_curves.at(i);
|
||||
} catch (std::out_of_range &e) {
|
||||
b1_isocurves = 0;
|
||||
}
|
||||
try {
|
||||
intersecting_isocurves = (int)ssx_isocsx_events.at(i).size();
|
||||
} catch (std::out_of_range &e) {
|
||||
intersecting_isocurves = 0;
|
||||
}
|
||||
|
||||
// b1si b2si finalevents b1ccurves b2ccurves b1_isocurve_xs total_isocurve_xs isocsx0_event0 ...
|
||||
fprintf(fp, "ssx %d %d %d %d %d %d %d", intersecting.first,
|
||||
intersecting.second, events, b1_clipped, b2_clipped,
|
||||
b1_isocurves, intersecting_isocurves);
|
||||
|
||||
if (ssx_isocsx_events.size() > i) {
|
||||
for (size_t j = 0; j < ssx_isocsx_events[i].size(); ++j) {
|
||||
fprintf(fp, " %d", ssx_isocsx_events[i][j]);
|
||||
}
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
// write out linked curve count
|
||||
if (linked_curve_count > 0) {
|
||||
fprintf(fp, "linkedcurves %d\n", linked_curve_count);
|
||||
}
|
||||
|
||||
// write out split faces
|
||||
size_t split_faces = split_face_outerloop_curves.size();
|
||||
if (split_faces > 0) {
|
||||
fprintf(fp, "splitfaces %d\n", (int)split_faces);
|
||||
}
|
||||
for (size_t i = 0; i < split_faces; ++i) {
|
||||
fprintf(fp, "splitface %d %d %d\n", (int)i,
|
||||
split_face_outerloop_curves[i],
|
||||
split_face_innerloop_curves[i]);
|
||||
}
|
||||
fclose(fp);
|
||||
BN_FREE_VLIST(&vlist_free_list, &vhead);
|
||||
}
|
||||
|
||||
HIDDEN double
|
||||
find_next_t(const ON_Curve* crv, double start_t, double step, double max_dist)
|
||||
{
|
||||
ON_Interval dom = crv->Domain();
|
||||
ON_3dPoint prev_pt = crv->PointAt(dom.ParameterAt(start_t));
|
||||
ON_3dPoint next_pt;
|
||||
|
||||
// ensure that (start + step) < 1.0
|
||||
if (start_t + step > 1.0) {
|
||||
step = 1.0 - start_t - BN_TOL_DIST;
|
||||
}
|
||||
|
||||
// reduce step until next point is within tolerance
|
||||
while (step > BN_TOL_DIST) {
|
||||
next_pt = crv->PointAt(dom.ParameterAt(start_t + step));
|
||||
|
||||
if (prev_pt.DistanceTo(next_pt) <= max_dist) {
|
||||
return start_t + step;
|
||||
}
|
||||
step /= 2.0;
|
||||
}
|
||||
// if we couldn't find a point within tolerance, give up and jump
|
||||
// to end of domain
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
void
|
||||
DebugPlot::Plot3DCurve(
|
||||
const ON_Curve *crv,
|
||||
const char *filename,
|
||||
unsigned char *color,
|
||||
struct bu_list *vlist /* = NULL */)
|
||||
{
|
||||
struct bu_list vhead_tmp;
|
||||
BU_LIST_INIT(&vhead_tmp);
|
||||
|
||||
struct bu_list *vhead = &vhead_tmp;
|
||||
if (vlist) {
|
||||
vhead = vlist;
|
||||
}
|
||||
|
||||
ON_Interval crv_dom = crv->Domain();
|
||||
|
||||
// Insert first point.
|
||||
point_t pt1;
|
||||
ON_3dPoint p;
|
||||
p = crv->PointAt(crv_dom.ParameterAt(0.0));
|
||||
VMOVE(pt1, p);
|
||||
BN_ADD_VLIST(&vlist_free_list, vhead, pt1, BN_VLIST_LINE_MOVE);
|
||||
|
||||
/* Dynamic sampling approach - start with an initial guess
|
||||
* for the next point of one tenth of the domain length
|
||||
* further down the domain from the previous value. Set a
|
||||
* maximum physical distance between points of 100 times
|
||||
* the model tolerance. Reduce the increment until the
|
||||
* tolerance is satisfied, then add the point and use it
|
||||
* as the starting point for the next calculation until
|
||||
* the whole domain is finished. Perhaps it would be more
|
||||
* ideal to base the tolerance on some fraction of the
|
||||
* curve bounding box dimensions?
|
||||
*/
|
||||
double t = 0.0;
|
||||
while (t < 1.0) {
|
||||
t = find_next_t(crv, t, 0.1, BN_TOL_DIST * 100);
|
||||
p = crv->PointAt(crv_dom.ParameterAt(t));
|
||||
VMOVE(pt1, p);
|
||||
|
||||
BN_ADD_VLIST(&vlist_free_list, vhead, pt1, BN_VLIST_LINE_DRAW);
|
||||
}
|
||||
|
||||
if (!vlist) {
|
||||
write_plot_to_file(filename, vhead, color);
|
||||
BN_FREE_VLIST(&vlist_free_list, vhead);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DebugPlot::Plot3DCurveFrom2D(
|
||||
const ON_Surface *surf,
|
||||
const ON_Curve *crv,
|
||||
const char *filename,
|
||||
unsigned char *color,
|
||||
bool decorate /* = false */)
|
||||
{
|
||||
struct bu_list vhead;
|
||||
BU_LIST_INIT(&vhead);
|
||||
|
||||
ON_Interval crv_dom = crv->Domain();
|
||||
|
||||
ON_3dPoint p, uv;
|
||||
|
||||
// Insert first point.
|
||||
point_t pt1, first_pt, last_pt, prev_pt;
|
||||
ON_3dVector normal;
|
||||
uv = crv->PointAt(crv_dom.ParameterAt(0.0));
|
||||
surf->EvNormal(uv.x, uv.y, p, normal);
|
||||
VMOVE(first_pt, p);
|
||||
|
||||
uv = crv->PointAt(crv_dom.ParameterAt(1.0));
|
||||
surf->EvNormal(uv.x, uv.y, p, normal);
|
||||
VMOVE(last_pt, p);
|
||||
|
||||
bool closed = false;
|
||||
if (VNEAR_EQUAL(first_pt, last_pt, BN_TOL_DIST)) {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
VMOVE(pt1, first_pt);
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, pt1, BN_VLIST_LINE_MOVE);
|
||||
|
||||
/* Dynamic sampling approach - start with an initial guess
|
||||
* for the next point of one tenth of the domain length
|
||||
* further down the domain from the previous value. Set a
|
||||
* maximum physical distance between points of 100 times
|
||||
* the model tolerance. Reduce the increment until the
|
||||
* tolerance is satisfied, then add the point and use it
|
||||
* as the starting point for the next calculation until
|
||||
* the whole domain is finished. Perhaps it would be more
|
||||
* ideal to base the tolerance on some fraction of the
|
||||
* curve bounding box dimensions?
|
||||
*/
|
||||
double t = 0.0;
|
||||
bool first = true;
|
||||
double min_mag = BN_TOL_DIST * 10.0;
|
||||
double mag_tan = min_mag;
|
||||
vect_t tangent = {0.0, 0.0, min_mag};
|
||||
vect_t perp, barb;
|
||||
while (t < 1.0) {
|
||||
t = find_next_t(crv, t, 0.1, BN_TOL_DIST * 100);
|
||||
|
||||
uv = crv->PointAt(crv_dom.ParameterAt(t));
|
||||
surf->EvNormal(uv.x, uv.y, p, normal);
|
||||
VMOVE(prev_pt, pt1);
|
||||
VMOVE(pt1, p);
|
||||
|
||||
if (first || !VNEAR_EQUAL(pt1, prev_pt, BN_TOL_DIST)) {
|
||||
VSUB2(tangent, pt1, prev_pt);
|
||||
}
|
||||
|
||||
if (decorate && first) {
|
||||
first = false;
|
||||
|
||||
mag_tan = DIST_PNT_PNT(prev_pt, pt1);
|
||||
mag_tan = FMAX(mag_tan, min_mag);
|
||||
|
||||
VUNITIZE(tangent);
|
||||
VCROSS(perp, tangent, normal);
|
||||
|
||||
if (!closed) {
|
||||
VSCALE(tangent, tangent, mag_tan);
|
||||
VUNITIZE(perp);
|
||||
VSCALE(perp, perp, mag_tan);
|
||||
|
||||
VADD3(barb, prev_pt, tangent, perp);
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, barb, BN_VLIST_LINE_DRAW);
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, prev_pt, BN_VLIST_LINE_MOVE);
|
||||
|
||||
VSCALE(perp, perp, -1.0);
|
||||
VADD3(barb, prev_pt, tangent, perp);
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, barb, BN_VLIST_LINE_DRAW);
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, prev_pt, BN_VLIST_LINE_MOVE);
|
||||
}
|
||||
}
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, pt1, BN_VLIST_LINE_DRAW);
|
||||
}
|
||||
if (decorate) {
|
||||
VUNITIZE(tangent);
|
||||
VSCALE(tangent, tangent, -mag_tan);
|
||||
|
||||
VCROSS(perp, tangent, normal);
|
||||
VUNITIZE(perp);
|
||||
VSCALE(perp, perp, mag_tan);
|
||||
|
||||
VADD2(barb, pt1, perp);
|
||||
if (!closed) {
|
||||
VADD2(barb, barb, tangent);
|
||||
}
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, barb, BN_VLIST_LINE_DRAW);
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, pt1, BN_VLIST_LINE_MOVE);
|
||||
|
||||
VSCALE(perp, perp, -1.0);
|
||||
VADD2(barb, pt1, perp);
|
||||
if (!closed) {
|
||||
VADD2(barb, barb, tangent);
|
||||
}
|
||||
BN_ADD_VLIST(&vlist_free_list, &vhead, barb, BN_VLIST_LINE_DRAW);
|
||||
}
|
||||
|
||||
write_plot_to_file(filename, &vhead, color);
|
||||
BN_FREE_VLIST(&vlist_free_list, &vhead);
|
||||
}
|
||||
|
||||
void
|
||||
DebugPlot::PlotBoundaryIsocurves(
|
||||
struct bu_list *vlist,
|
||||
const ON_Surface &surf,
|
||||
int knot_dir)
|
||||
{
|
||||
int surf_dir = 1 - knot_dir;
|
||||
int knot_count = surf.SpanCount(surf_dir) + 1;
|
||||
|
||||
double *surf_knots = new double[knot_count];
|
||||
surf.GetSpanVector(surf_dir, surf_knots);
|
||||
|
||||
// knots that can be boundaries of Bezier patches
|
||||
ON_SimpleArray<double> surf_bknots;
|
||||
surf_bknots.Append(surf_knots[0]);
|
||||
for (int i = 1; i < knot_count; i++) {
|
||||
if (surf_knots[i] > *(surf_bknots.Last())) {
|
||||
surf_bknots.Append(surf_knots[i]);
|
||||
}
|
||||
}
|
||||
delete[] surf_knots;
|
||||
|
||||
if (surf.IsClosed(surf_dir)) {
|
||||
surf_bknots.Remove();
|
||||
}
|
||||
|
||||
for (int i = 0; i < surf_bknots.Count(); i++) {
|
||||
ON_Curve *surf_boundary_iso = surf.IsoCurve(knot_dir, surf_bknots[i]);
|
||||
Plot3DCurve(surf_boundary_iso, NULL, NULL, vlist);
|
||||
delete surf_boundary_iso;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DebugPlot::PlotSurface(
|
||||
const ON_Surface &surf,
|
||||
const char *filename,
|
||||
unsigned char *color)
|
||||
{
|
||||
struct bu_list vhead;
|
||||
BU_LIST_INIT(&vhead);
|
||||
|
||||
PlotBoundaryIsocurves(&vhead, surf, 0);
|
||||
PlotBoundaryIsocurves(&vhead, surf, 1);
|
||||
|
||||
write_plot_to_file(filename, &vhead, color);
|
||||
|
||||
BN_FREE_VLIST(&vlist_free_list, &vhead);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DebugPlot::Surfaces(const ON_Brep *brep1, const ON_Brep *brep2)
|
||||
{
|
||||
if (!brep1 || !brep2) {
|
||||
std::cerr << "error: dplot_surfaces: NULL args\n";
|
||||
return;
|
||||
}
|
||||
|
||||
brep1_surf_count = brep1->m_S.Count();
|
||||
for (int i = 0; i < brep1->m_S.Count(); i++) {
|
||||
ON_Surface *surf = brep1->m_S[i];
|
||||
std::ostringstream filename;
|
||||
filename << prefix << "_brep1_surface" << i << ".plot3";
|
||||
PlotSurface(*surf, filename.str().c_str(), surface1_color);
|
||||
}
|
||||
|
||||
brep2_surf_count = brep2->m_S.Count();
|
||||
for (int i = 0; i < brep2->m_S.Count(); i++) {
|
||||
ON_Surface *surf = brep2->m_S[i];
|
||||
std::ostringstream filename;
|
||||
filename << prefix << "_brep2_surface" << i << ".plot3";
|
||||
PlotSurface(*surf, filename.str().c_str(), surface2_color);
|
||||
}
|
||||
have_surfaces = true;
|
||||
}
|
||||
|
||||
int get_subcurve_inside_faces(const ON_Brep *brep1, const ON_Brep *brep2, int face_i1, int face_i2, ON_SSX_EVENT *event);
|
||||
|
||||
void
|
||||
DebugPlot::SSX(
|
||||
const ON_ClassArray<ON_SSX_EVENT> &events,
|
||||
const ON_Brep *brep1, int brep1_surf,
|
||||
const ON_Brep *brep2, int brep2_surf)
|
||||
{
|
||||
ON_Surface *surf;
|
||||
std::ostringstream filename;
|
||||
|
||||
// create highlighted plot of brep1 surface if it doesn't exist
|
||||
filename << prefix << "_highlight_brep1_surface" << brep1_surf << ".plot3";
|
||||
if (!bu_file_exists(filename.str().c_str(), NULL)) {
|
||||
surf = brep1->m_S[brep1_surf];
|
||||
PlotSurface(*surf, filename.str().c_str(), surface1_highlight_color);
|
||||
}
|
||||
|
||||
// create highlighted plot of brep2 surface if it doesn't exist
|
||||
filename.str("");
|
||||
filename << prefix << "_highlight_brep2_surface" << brep2_surf << ".plot3";
|
||||
if (!bu_file_exists(filename.str().c_str(), NULL)) {
|
||||
surf = brep2->m_S[brep2_surf];
|
||||
PlotSurface(*surf, filename.str().c_str(), surface2_highlight_color);
|
||||
}
|
||||
|
||||
// create plot of the intersections between these surfaces
|
||||
surf = brep1->m_S[brep1_surf];
|
||||
size_t ssx_idx = intersecting_surfaces.size();
|
||||
int plot_count = 0;
|
||||
for (int i = 0; i < events.Count(); ++i) {
|
||||
filename.str("");
|
||||
filename << prefix << "_ssx" << ssx_idx << "_event" << plot_count <<
|
||||
".plot3";
|
||||
|
||||
if (events[i].m_type == ON_SSX_EVENT::ssx_tangent) {
|
||||
Plot3DCurveFrom2D(surf, events[i].m_curveA,
|
||||
filename.str().c_str(), tangent_color, true);
|
||||
++plot_count;
|
||||
} else if (events[i].m_type == ON_SSX_EVENT::ssx_transverse) {
|
||||
Plot3DCurveFrom2D(surf, events[i].m_curveA,
|
||||
filename.str().c_str(), transverse_color, true);
|
||||
++plot_count;
|
||||
} else if (events[i].m_type == ON_SSX_EVENT::ssx_overlap) {
|
||||
Plot3DCurveFrom2D(surf, events[i].m_curveA,
|
||||
filename.str().c_str(), overlap_color, true);
|
||||
++plot_count;
|
||||
}
|
||||
}
|
||||
// stash surface indices and event count
|
||||
std::pair<int, int> ssx_pair(brep1_surf, brep2_surf);
|
||||
intersecting_surfaces.push_back(ssx_pair);
|
||||
ssx_events.push_back(plot_count);
|
||||
}
|
||||
|
||||
void
|
||||
DebugPlot::IsoCSX(
|
||||
const ON_SimpleArray<ON_X_EVENT> &events,
|
||||
const ON_Curve *isocurve,
|
||||
bool is_brep1_iso) // is the isocurve from brep1?
|
||||
{
|
||||
size_t ssx_idx = intersecting_surfaces.size();
|
||||
|
||||
// create plot of the intersections between the curve and surface
|
||||
while (ssx_isocsx_events.size() < (ssx_idx + 1)) {
|
||||
ssx_isocsx_events.push_back(std::vector<int>());
|
||||
}
|
||||
size_t isocsx_idx = ssx_isocsx_events[ssx_idx].size();
|
||||
int plot_count = 0;
|
||||
for (int i = 0; i < events.Count(); ++i) {
|
||||
if (events[i].m_type == ON_X_EVENT::csx_overlap) {
|
||||
std::ostringstream filename;
|
||||
filename << prefix << "_ssx" << ssx_idx << "_isocsx" << isocsx_idx
|
||||
<< "_event" << plot_count++ << ".plot3";
|
||||
|
||||
try {
|
||||
ON_Curve *event_curve = sub_curve(isocurve, events[i].m_a[0],
|
||||
events[i].m_a[1]);
|
||||
Plot3DCurve(event_curve, filename.str().c_str(), overlap_color);
|
||||
} catch (InvalidInterval &e) {
|
||||
std::cerr << "error: IsoCSX event contains degenerate interval\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (plot_count) {
|
||||
// create highlighted plot of isocurve if it doesn't already exist
|
||||
std::ostringstream filename;
|
||||
filename << prefix << "_highlight_ssx" << ssx_idx << "_isocurve" <<
|
||||
isocsx_idx << ".plot3";
|
||||
if (!bu_file_exists(filename.str().c_str(), NULL)) {
|
||||
if (is_brep1_iso) {
|
||||
Plot3DCurve(isocurve, filename.str().c_str(),
|
||||
surface1_highlight_color);
|
||||
} else {
|
||||
Plot3DCurve(isocurve, filename.str().c_str(),
|
||||
surface2_highlight_color);
|
||||
}
|
||||
}
|
||||
|
||||
// remember event count for this isocsx
|
||||
ssx_isocsx_events[ssx_idx].push_back(plot_count);
|
||||
|
||||
// remember how many events are for brep1 isocurve and brep2 surface,
|
||||
if (is_brep1_iso) {
|
||||
while (ssx_isocsx_brep1_curves.size() < (ssx_idx + 1)) {
|
||||
ssx_isocsx_brep1_curves.push_back(0);
|
||||
}
|
||||
++ssx_isocsx_brep1_curves[ssx_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DebugPlot::ClippedFaceCurves(
|
||||
const ON_Surface *surf1,
|
||||
const ON_Surface *surf2,
|
||||
const ON_SimpleArray<ON_Curve *> &face1_curves,
|
||||
const ON_SimpleArray<ON_Curve *> &face2_curves)
|
||||
{
|
||||
// plot clipped tangent/transverse/overlap curves
|
||||
size_t ssx_idx = intersecting_surfaces.size() - 1;
|
||||
for (int i = 0; i < face1_curves.Count(); ++i) {
|
||||
std::ostringstream filename;
|
||||
filename << prefix << "_ssx" << ssx_idx << "_brep1face_clipped_curve" << i << ".plot3";
|
||||
Plot3DCurveFrom2D(surf1, face1_curves[i], filename.str().c_str(),
|
||||
surface1_highlight_color, true);
|
||||
}
|
||||
for (int i = 0; i < face2_curves.Count(); ++i) {
|
||||
std::ostringstream filename;
|
||||
filename << prefix << "_ssx" << ssx_idx << "_brep2face_clipped_curve" << i << ".plot3";
|
||||
Plot3DCurveFrom2D(surf2, face2_curves[i], filename.str().c_str(),
|
||||
surface2_highlight_color, true);
|
||||
}
|
||||
|
||||
while (ssx_clipped_curves.size() < (ssx_idx + 1)) {
|
||||
ssx_clipped_curves.push_back(std::pair<int, int>(0, 0));
|
||||
}
|
||||
std::pair<int, int> counts(face1_curves.Count(), face2_curves.Count());
|
||||
ssx_clipped_curves[ssx_idx] = counts;
|
||||
}
|
||||
|
||||
struct TrimmedFace {
|
||||
// curve segments in the face's outer loop
|
||||
ON_SimpleArray<ON_Curve *> m_outerloop;
|
||||
// several inner loops, each has some curves
|
||||
std::vector<ON_SimpleArray<ON_Curve *> > m_innerloop;
|
||||
const ON_BrepFace *m_face;
|
||||
enum {
|
||||
UNKNOWN = -1,
|
||||
NOT_BELONG = 0,
|
||||
BELONG = 1
|
||||
} m_belong_to_final;
|
||||
bool m_rev;
|
||||
|
||||
// Default constructor
|
||||
TrimmedFace()
|
||||
{
|
||||
m_face = NULL;
|
||||
m_belong_to_final = UNKNOWN;
|
||||
m_rev = false;
|
||||
}
|
||||
|
||||
// Destructor
|
||||
~TrimmedFace()
|
||||
{
|
||||
// Delete the curve segments if it's not belong to the result.
|
||||
if (m_belong_to_final != BELONG) {
|
||||
for (int i = 0; i < m_outerloop.Count(); i++) {
|
||||
if (m_outerloop[i]) {
|
||||
delete m_outerloop[i];
|
||||
m_outerloop[i] = NULL;
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < m_innerloop.size(); i++) {
|
||||
for (int j = 0; j < m_innerloop[i].Count(); j++) {
|
||||
if (m_innerloop[i][j]) {
|
||||
delete m_innerloop[i][j];
|
||||
m_innerloop[i][j] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrimmedFace *Duplicate() const
|
||||
{
|
||||
TrimmedFace *out = new TrimmedFace();
|
||||
out->m_face = m_face;
|
||||
for (int i = 0; i < m_outerloop.Count(); i++) {
|
||||
if (m_outerloop[i]) {
|
||||
out->m_outerloop.Append(m_outerloop[i]->Duplicate());
|
||||
}
|
||||
}
|
||||
out->m_innerloop = m_innerloop;
|
||||
for (unsigned int i = 0; i < m_innerloop.size(); i++) {
|
||||
for (int j = 0; j < m_innerloop[i].Count(); j++) {
|
||||
if (m_innerloop[i][j]) {
|
||||
out->m_innerloop[i][j] = m_innerloop[i][j]->Duplicate();
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
DebugPlot::SplitFaces(
|
||||
const ON_ClassArray<ON_SimpleArray<TrimmedFace *> > &split_faces)
|
||||
{
|
||||
for (int i = 0; i < split_faces.Count(); ++i) {
|
||||
for (int j = 0; j < split_faces[i].Count(); ++j) {
|
||||
TrimmedFace *face = split_faces[i][j];
|
||||
|
||||
unsigned char *outerloop_color = unknown_outerloop_color;
|
||||
unsigned char *innerloop_color = unknown_innerloop_color;
|
||||
switch (face->m_belong_to_final) {
|
||||
case TrimmedFace::NOT_BELONG:
|
||||
outerloop_color = rejected_outerloop_color;
|
||||
innerloop_color = rejected_innerloop_color;
|
||||
break;
|
||||
case TrimmedFace::BELONG:
|
||||
outerloop_color = accepted_outerloop_color;
|
||||
innerloop_color = accepted_innerloop_color;
|
||||
break;
|
||||
default:
|
||||
outerloop_color = unknown_outerloop_color;
|
||||
innerloop_color = unknown_innerloop_color;
|
||||
}
|
||||
|
||||
int split_face_count = split_face_outerloop_curves.size();
|
||||
for (int k = 0; k < face->m_outerloop.Count(); ++k) {
|
||||
std::ostringstream filename;
|
||||
filename << prefix << "_split_face" << split_face_count <<
|
||||
"_outerloop_curve" << k << ".plot3";
|
||||
|
||||
Plot3DCurveFrom2D(face->m_face->SurfaceOf(),
|
||||
face->m_outerloop[k], filename.str().c_str(),
|
||||
outerloop_color);
|
||||
}
|
||||
split_face_outerloop_curves.push_back(face->m_outerloop.Count());
|
||||
|
||||
int innerloop_count = 0;
|
||||
for (size_t k = 0; k < face->m_innerloop.size(); ++k) {
|
||||
for (int l = 0; l < face->m_innerloop[k].Count(); ++l) {
|
||||
std::ostringstream filename;
|
||||
filename << prefix << "_split_face" << split_face_count <<
|
||||
"_innerloop_curve" << innerloop_count++ << ".plot3";
|
||||
|
||||
Plot3DCurveFrom2D(face->m_face->SurfaceOf(),
|
||||
face->m_innerloop[k][l], filename.str().c_str(),
|
||||
innerloop_color);
|
||||
}
|
||||
}
|
||||
split_face_innerloop_curves.push_back(innerloop_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void append_to_polycurve(ON_Curve *curve, ON_PolyCurve &polycurve);
|
||||
|
||||
struct SSICurve {
|
||||
ON_Curve *m_curve;
|
||||
|
||||
SSICurve()
|
||||
{
|
||||
m_curve = NULL;
|
||||
}
|
||||
|
||||
SSICurve(ON_Curve *curve)
|
||||
{
|
||||
m_curve = curve;
|
||||
}
|
||||
|
||||
SSICurve *Duplicate() const
|
||||
{
|
||||
SSICurve *out = new SSICurve();
|
||||
if (out != NULL) {
|
||||
*out = *this;
|
||||
out->m_curve = m_curve->Duplicate();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
struct LinkedCurve {
|
||||
private:
|
||||
ON_Curve *m_curve; // an explicit storage of the whole curve
|
||||
public:
|
||||
// The curves contained in this LinkedCurve, including
|
||||
// the information needed by the connectivity graph
|
||||
ON_SimpleArray<SSICurve> m_ssi_curves;
|
||||
|
||||
// Default constructor
|
||||
LinkedCurve()
|
||||
{
|
||||
m_curve = NULL;
|
||||
}
|
||||
|
||||
~LinkedCurve()
|
||||
{
|
||||
if (m_curve) {
|
||||
delete m_curve;
|
||||
}
|
||||
m_curve = NULL;
|
||||
}
|
||||
|
||||
LinkedCurve &operator= (const LinkedCurve &_lc)
|
||||
{
|
||||
m_curve = _lc.m_curve ? _lc.m_curve->Duplicate() : NULL;
|
||||
m_ssi_curves = _lc.m_ssi_curves;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ON_3dPoint PointAtStart() const
|
||||
{
|
||||
if (m_ssi_curves.Count()) {
|
||||
return m_ssi_curves[0].m_curve->PointAtStart();
|
||||
} else {
|
||||
return ON_3dPoint::UnsetPoint;
|
||||
}
|
||||
}
|
||||
|
||||
ON_3dPoint PointAtEnd() const
|
||||
{
|
||||
if (m_ssi_curves.Count()) {
|
||||
return m_ssi_curves.Last()->m_curve->PointAtEnd();
|
||||
} else {
|
||||
return ON_3dPoint::UnsetPoint;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsClosed() const
|
||||
{
|
||||
if (m_ssi_curves.Count() == 0) {
|
||||
return false;
|
||||
}
|
||||
return PointAtStart().DistanceTo(PointAtEnd()) < ON_ZERO_TOLERANCE;
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
// Check whether the curve has "gaps".
|
||||
for (int i = 1; i < m_ssi_curves.Count(); i++) {
|
||||
if (m_ssi_curves[i].m_curve->PointAtStart().DistanceTo(m_ssi_curves[i - 1].m_curve->PointAtEnd()) >= ON_ZERO_TOLERANCE) {
|
||||
bu_log("The LinkedCurve is not valid.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Reverse()
|
||||
{
|
||||
ON_SimpleArray<SSICurve> new_array;
|
||||
for (int i = m_ssi_curves.Count() - 1; i >= 0; i--) {
|
||||
if (!m_ssi_curves[i].m_curve->Reverse()) {
|
||||
return false;
|
||||
}
|
||||
new_array.Append(m_ssi_curves[i]);
|
||||
}
|
||||
m_ssi_curves = new_array;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Append(const LinkedCurve &lc)
|
||||
{
|
||||
m_ssi_curves.Append(lc.m_ssi_curves.Count(), lc.m_ssi_curves.Array());
|
||||
}
|
||||
|
||||
void Append(const SSICurve &sc)
|
||||
{
|
||||
m_ssi_curves.Append(sc);
|
||||
}
|
||||
|
||||
void AppendCurvesToArray(ON_SimpleArray<ON_Curve *> &arr) const
|
||||
{
|
||||
for (int i = 0; i < m_ssi_curves.Count(); i++) {
|
||||
arr.Append(m_ssi_curves[i].m_curve->Duplicate());
|
||||
}
|
||||
}
|
||||
|
||||
const ON_Curve *Curve()
|
||||
{
|
||||
if (m_curve != NULL) {
|
||||
return m_curve;
|
||||
}
|
||||
if (m_ssi_curves.Count() == 0 || !IsValid()) {
|
||||
return NULL;
|
||||
}
|
||||
ON_PolyCurve *polycurve = new ON_PolyCurve;
|
||||
for (int i = 0; i < m_ssi_curves.Count(); i++) {
|
||||
append_to_polycurve(m_ssi_curves[i].m_curve->Duplicate(), *polycurve);
|
||||
}
|
||||
m_curve = polycurve;
|
||||
return m_curve;
|
||||
}
|
||||
|
||||
const ON_3dPoint PointAt(double t)
|
||||
{
|
||||
const ON_Curve *c = Curve();
|
||||
if (c == NULL) {
|
||||
return ON_3dPoint::UnsetPoint;
|
||||
}
|
||||
return c->PointAt(t);
|
||||
}
|
||||
|
||||
const ON_Interval Domain()
|
||||
{
|
||||
const ON_Curve *c = Curve();
|
||||
if (c == NULL) {
|
||||
return ON_Interval::EmptyInterval;
|
||||
}
|
||||
return c->Domain();
|
||||
}
|
||||
|
||||
ON_Curve *SubCurve(double t1, double t2)
|
||||
{
|
||||
const ON_Curve *c = Curve();
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
try {
|
||||
return sub_curve(c, t1, t2);
|
||||
} catch (InvalidInterval &e) {
|
||||
bu_log("%s", e.what());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
DebugPlot::LinkedCurves(
|
||||
const ON_Surface *surf,
|
||||
ON_ClassArray<LinkedCurve> &linked_curves)
|
||||
{
|
||||
for (int i = 0; i < linked_curves.Count(); ++i) {
|
||||
const ON_Curve *linked_curve = linked_curves[i].Curve();
|
||||
|
||||
std::ostringstream filename;
|
||||
filename << prefix << "_linked_curve" << linked_curve_count++ << ".plot3";
|
||||
|
||||
Plot3DCurveFrom2D(surf, linked_curve, filename.str().c_str(), transverse_color);
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// tab-width: 8
|
||||
// mode: C++
|
||||
// c-basic-offset: 4
|
||||
// indent-tabs-mode: t
|
||||
// c-file-style: "stroustrup"
|
||||
// End:
|
||||
// ex: shiftwidth=4 tabstop=8
|
||||
@@ -0,0 +1,141 @@
|
||||
/* D E B U G _ P L O T . H
|
||||
* BRL-CAD
|
||||
*
|
||||
* Copyright (c) 2014 United States Government as represented by
|
||||
* the U.S. Army Research Laboratory.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; see the file named COPYING for more
|
||||
* information.
|
||||
*/
|
||||
/** @file debug_plot.h
|
||||
*
|
||||
* Class used to write out unix plot files representing brep geometry
|
||||
* and intersection events from various stages of brep boolean
|
||||
* evaluation.
|
||||
*
|
||||
* Also outputs a parsable log file with implicit information about
|
||||
* the output plot files.
|
||||
*/
|
||||
|
||||
#ifndef DEBUG_PLOT_H
|
||||
#define DEBUG_PLOT_H
|
||||
#include "bu/list.h"
|
||||
#include "raytrace.h"
|
||||
|
||||
struct TrimmedFace;
|
||||
struct LinkedCurve;
|
||||
|
||||
class DebugPlot {
|
||||
public:
|
||||
// prefix all dplot output files with 'basename'
|
||||
DebugPlot(const char *basename);
|
||||
|
||||
~DebugPlot();
|
||||
|
||||
// write plot files for all surfaces of two breps
|
||||
void Surfaces(const ON_Brep *brep1, const ON_Brep *brep2);
|
||||
|
||||
// record a surface surface intersection
|
||||
void SSX(
|
||||
const ON_ClassArray<ON_SSX_EVENT> &events,
|
||||
const ON_Brep *brep1, int brep1_surf,
|
||||
const ON_Brep *brep2, int brep2_surf);
|
||||
|
||||
// record surface surface isocurve intersections
|
||||
void IsoCSX(
|
||||
const ON_SimpleArray<ON_X_EVENT> &events,
|
||||
const ON_Curve *isocurve,
|
||||
bool is_brep1_iso);
|
||||
|
||||
// record clipped surface-surface intersection curves
|
||||
void ClippedFaceCurves(
|
||||
const ON_Surface *surf1,
|
||||
const ON_Surface *surf2,
|
||||
const ON_SimpleArray<ON_Curve *> &face1_curves,
|
||||
const ON_SimpleArray<ON_Curve *> &face2_curves);
|
||||
|
||||
// write out the log file that the dplot command references to
|
||||
// navigate the generated plot files
|
||||
void WriteLog();
|
||||
|
||||
// get the number of intersecting surface pairs recorded
|
||||
int SurfacePairs();
|
||||
|
||||
// get the number of isocurves that intersect either surface in
|
||||
// given surface pair
|
||||
int IntersectingIsocurves(int ssx_idx);
|
||||
|
||||
// get the number of linked curves recorded
|
||||
int LinkedCurves();
|
||||
|
||||
void SplitFaces(
|
||||
const ON_ClassArray<ON_SimpleArray<TrimmedFace *> > &split_faces);
|
||||
|
||||
void LinkedCurves(
|
||||
const ON_Surface *surf,
|
||||
ON_ClassArray<LinkedCurve> &linked_curves);
|
||||
|
||||
void
|
||||
Plot3DCurveFrom2D(
|
||||
const ON_Surface *surf,
|
||||
const ON_Curve *crv,
|
||||
const char *filename,
|
||||
unsigned char *color,
|
||||
bool decorate = false
|
||||
);
|
||||
|
||||
void
|
||||
Plot3DCurve(
|
||||
const ON_Curve *crv,
|
||||
const char *filename,
|
||||
unsigned char *color,
|
||||
struct bu_list *vlist = NULL);
|
||||
|
||||
private:
|
||||
struct bu_list vlist_free_list;
|
||||
std::string prefix;
|
||||
bool have_surfaces;
|
||||
int brep1_surf_count;
|
||||
int brep2_surf_count;
|
||||
int linked_curve_count;
|
||||
std::vector< std::pair<int, int> > intersecting_surfaces; // ssx surface index pairs
|
||||
std::vector<int> ssx_events; // num final events of each ssx
|
||||
std::vector< std::vector<int> > ssx_isocsx_events; // num events for each isocsx of each ssx
|
||||
std::vector<int> ssx_isocsx_brep1_curves; // num ssx isocsx events using brep1 isocurves
|
||||
std::vector< std::pair<int, int> > ssx_clipped_curves; // num clipped intersection curves
|
||||
std::vector<int> split_face_outerloop_curves;
|
||||
std::vector<int> split_face_innerloop_curves;
|
||||
|
||||
void PlotSurface(
|
||||
const ON_Surface &surf,
|
||||
const char *filename,
|
||||
unsigned char *color);
|
||||
|
||||
void
|
||||
PlotBoundaryIsocurves(
|
||||
struct bu_list *vlist,
|
||||
const ON_Surface &surf,
|
||||
int knot_dir);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* tab-width: 8
|
||||
* mode: C
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "stroustrup"
|
||||
* End:
|
||||
* ex: shiftwidth=4 tabstop=8
|
||||
*/
|
||||
@@ -21,6 +21,8 @@
|
||||
*
|
||||
* Implementation of intersection routines openNURBS left out.
|
||||
*
|
||||
* Additional documentation can be found in the "NURBS Boolean Evaluation
|
||||
* Development Guide" docbook article (bool_eval_development.html).
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
@@ -38,42 +40,15 @@
|
||||
#include "brep/defines.h"
|
||||
#include "brep/intersect.h"
|
||||
#include "brep/util.h"
|
||||
#include "debug_plot.h"
|
||||
#include "brep_except.h"
|
||||
#include "brep_defines.h"
|
||||
|
||||
extern DebugPlot *dplot;
|
||||
|
||||
// Whether to output the debug messages about b-rep intersections.
|
||||
static int DEBUG_BREP_INTERSECT = 0;
|
||||
|
||||
// The maximal depth for subdivision - trade-off between accuracy and
|
||||
// performance.
|
||||
#define NR_MAX_DEPTH 8
|
||||
#define MAX_PCI_DEPTH NR_MAX_DEPTH
|
||||
#define MAX_PSI_DEPTH NR_MAX_DEPTH
|
||||
#define MAX_CCI_DEPTH NR_MAX_DEPTH
|
||||
#define MAX_CSI_DEPTH NR_MAX_DEPTH
|
||||
#define MAX_SSI_DEPTH NR_MAX_DEPTH
|
||||
|
||||
|
||||
// We make the default tolerance for PSI the same as that of curve and
|
||||
// surface intersections defined by openNURBS (see opennurbs_curve.h
|
||||
// and opennurbs_surface.h).
|
||||
#define NR_DEFAULT_TOLERANCE 0.001
|
||||
#define PCI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
#define PSI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
#define CCI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
#define CSI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
#define SSI_DEFAULT_TOLERANCE NR_DEFAULT_TOLERANCE
|
||||
|
||||
// Used to prevent an infinite loop in the unlikely event that we
|
||||
// can't provide a good starting point for the Newton-Raphson
|
||||
// Iteration.
|
||||
#define NR_MAX_ITERATIONS 100
|
||||
#define PCI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
#define PSI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
#define CCI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
#define CSI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
#define SSI_MAX_ITERATIONS NR_MAX_ITERATIONS
|
||||
|
||||
class XEventProxy {
|
||||
public:
|
||||
XEventProxy(ON_X_EVENT::TYPE type);
|
||||
@@ -2556,10 +2531,29 @@ newton_ssi(double &uA, double &vA, double &uB, double &vB, const ON_Surface *sur
|
||||
return (pointA.DistanceTo(pointB) < isect_tol) && !std::isnan(uA) && !std::isnan(vA) && !std::isnan(uB) & !std::isnan(vB);
|
||||
}
|
||||
|
||||
// if curve end is greater than tol distance from pt, append a linear
|
||||
// segment to the curve so it extends to the pt
|
||||
HIDDEN void
|
||||
extend_curve_end_to_pt(ON_Curve *&curve, ON_3dPoint pt, double tol)
|
||||
{
|
||||
ON_NurbsCurve *nc = curve->NurbsCurve();
|
||||
if (nc->PointAtEnd().DistanceTo(pt) > tol) {
|
||||
ON_LineCurve line_bridge(nc->PointAtEnd(), pt);
|
||||
|
||||
ON_NurbsCurve bridge;
|
||||
if (line_bridge.GetNurbForm(bridge)) {
|
||||
nc->Append(bridge);
|
||||
}
|
||||
delete curve;
|
||||
curve = nc;
|
||||
}
|
||||
}
|
||||
|
||||
HIDDEN ON_Curve *
|
||||
link_curves(ON_Curve *&c1, ON_Curve *&c2)
|
||||
{
|
||||
extend_curve_end_to_pt(c1, c2->PointAtStart(), ON_ZERO_TOLERANCE);
|
||||
|
||||
ON_NurbsCurve *nc1 = c1->NurbsCurve();
|
||||
ON_NurbsCurve *nc2 = c2->NurbsCurve();
|
||||
if (nc1 && nc2) {
|
||||
@@ -2578,6 +2572,16 @@ link_curves(ON_Curve *&c1, ON_Curve *&c2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if curve start and end are within tolerance, append a linear
|
||||
// segment to the curve to close it completely so it passes
|
||||
// IsClosed() tests
|
||||
HIDDEN void
|
||||
fill_gap_if_closed(ON_Curve *&curve, double tol)
|
||||
{
|
||||
if (curve->PointAtStart().DistanceTo(curve->PointAtEnd()) <= tol) {
|
||||
extend_curve_end_to_pt(curve, curve->PointAtStart(), ON_ZERO_TOLERANCE);
|
||||
}
|
||||
}
|
||||
|
||||
struct OverlapSegment {
|
||||
ON_Curve *m_curve3d, *m_curveA, *m_curveB;
|
||||
@@ -2969,17 +2973,10 @@ is_curve_on_overlap_boundary(
|
||||
bool ret = false;
|
||||
|
||||
if (iso.overlap_t[0] < iso.overlap_t[1]) {
|
||||
bool at_first_knot = iso.src.knot.IsFirst();
|
||||
bool at_last_knot = iso.src.knot.IsLast();
|
||||
bool closed_at_iso = surf1->IsClosed(1 - iso.src.knot.dir) != 0;
|
||||
int location = isocurve_surface_overlap_location(iso, surf1, surf2,
|
||||
surf2_tree, isect_tol, isect_tol1);
|
||||
|
||||
ret = true;
|
||||
if (closed_at_iso || (!at_first_knot && !at_last_knot)) {
|
||||
int location = isocurve_surface_overlap_location(iso, surf1,
|
||||
surf2, surf2_tree, isect_tol, isect_tol1);
|
||||
|
||||
ret = (location == ON_OVERLAP_BOUNDARY);
|
||||
}
|
||||
ret = (location == ON_OVERLAP_BOUNDARY);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -3513,6 +3510,7 @@ set_ssx_event_from_curves(
|
||||
HIDDEN void
|
||||
find_overlap_boundary_curves(
|
||||
ON_SimpleArray<OverlapSegment *> &overlaps,
|
||||
ON_ClassArray<ON_SSX_EVENT> &csx_events,
|
||||
ON_3dPointArray &isocurve_3d,
|
||||
ON_2dPointArray &isocurveA_2d,
|
||||
ON_2dPointArray &isocurveB_2d,
|
||||
@@ -3554,6 +3552,9 @@ find_overlap_boundary_curves(
|
||||
ON_Intersect(surf1_isocurve, surf2, events, isect_tol,
|
||||
overlap_tol, 0, 0, 0, &overlap2d);
|
||||
|
||||
dplot->IsoCSX(events, surf1_isocurve, is_surfA_iso);
|
||||
dplot->WriteLog();
|
||||
|
||||
append_csx_event_points(isocurve_3d, isocurve2_2d, events);
|
||||
|
||||
for (int k = 0; k < events.Count(); k++) {
|
||||
@@ -3575,6 +3576,36 @@ find_overlap_boundary_curves(
|
||||
if (curve_on_overlap_boundary) {
|
||||
append_overlap_segments(overlaps, iso, overlap2d[k],
|
||||
surf1);
|
||||
} else {
|
||||
// the intersection isn't part of a
|
||||
// surface-surface overlap, but we want it all
|
||||
// the same
|
||||
ON_SimpleArray<OverlapSegment *> tmp_overlaps;
|
||||
|
||||
append_overlap_segments(tmp_overlaps, iso, overlap2d[k], surf1);
|
||||
|
||||
for (int l = 0; l < tmp_overlaps.Count(); ++l) {
|
||||
ON_SSX_EVENT ssx_event;
|
||||
|
||||
int ret = set_ssx_event_from_curves(ssx_event,
|
||||
tmp_overlaps[l]->m_curve3d,
|
||||
tmp_overlaps[l]->m_curveA,
|
||||
tmp_overlaps[l]->m_curveB, surfA, surfB);
|
||||
if (ret != 0) {
|
||||
bu_log("warning: reverse failed.");
|
||||
}
|
||||
csx_events.Append(ssx_event);
|
||||
|
||||
// set the curves to NULL so they aren't
|
||||
// deleted by destructors
|
||||
tmp_overlaps[l]->m_curve3d = NULL;
|
||||
tmp_overlaps[l]->m_curveA = NULL;
|
||||
tmp_overlaps[l]->m_curveB = NULL;
|
||||
|
||||
ssx_event.m_curve3d = NULL;
|
||||
ssx_event.m_curveA = NULL;
|
||||
ssx_event.m_curveB = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3735,12 +3766,25 @@ ON_Intersect(const ON_Surface *surfA,
|
||||
ON_2dPointArray curve_uvA, curve_uvB, tmp_curve_uvA, tmp_curve_uvB;
|
||||
|
||||
ON_SimpleArray<OverlapSegment *> overlaps;
|
||||
find_overlap_boundary_curves(overlaps, tmp_curvept, tmp_curve_uvA,
|
||||
ON_ClassArray<ON_SSX_EVENT> csx_events;
|
||||
|
||||
find_overlap_boundary_curves(overlaps, csx_events, tmp_curvept, tmp_curve_uvA,
|
||||
tmp_curve_uvB, surfA, surfB, treeA, treeB, isect_tol, isect_tolA,
|
||||
isect_tolB, overlap_tol);
|
||||
|
||||
split_overlaps_at_intersections(overlaps, surfA, surfB, treeA, treeB,
|
||||
isect_tol, isect_tolA, isect_tolB);
|
||||
|
||||
// add csx_events
|
||||
for (int i = 0; i < csx_events.Count(); ++i) {
|
||||
x.Append(csx_events[i]);
|
||||
|
||||
// set the curves to NULL so they aren't deleted by destructor
|
||||
csx_events[i].m_curve3d = NULL;
|
||||
csx_events[i].m_curveA = NULL;
|
||||
csx_events[i].m_curveB = NULL;
|
||||
}
|
||||
|
||||
// find the neighbors for every overlap segment
|
||||
ON_SimpleArray<bool> start_linked(overlaps.Count()), end_linked(overlaps.Count());
|
||||
for (int i = 0; i < overlaps.Count(); i++) {
|
||||
@@ -3875,6 +3919,9 @@ ON_Intersect(const ON_Surface *surfA,
|
||||
delete overlaps[j];
|
||||
overlaps[j] = NULL;
|
||||
}
|
||||
fill_gap_if_closed(overlaps[i]->m_curve3d, isect_tol);
|
||||
fill_gap_if_closed(overlaps[i]->m_curveA, isect_tolA);
|
||||
fill_gap_if_closed(overlaps[i]->m_curveB, isect_tolB);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,14 +14,8 @@ set(distcheck_files
|
||||
vsp.stp
|
||||
)
|
||||
|
||||
BRLCAD_ADDEXEC(brep_cdt_mesh brep_cdt_mesh.cpp "libbrep;libbg;libbn;libbu" TEST)
|
||||
|
||||
BRLCAD_ADDEXEC(test_point_intersect test_point_intersect.cpp "libbrep" NO_STRICT NO_INSTALL)
|
||||
|
||||
BRLCAD_ADDEXEC(test_curve_intersect test_curve_intersect.cpp "libbrep" NO_STRICT NO_INSTALL)
|
||||
|
||||
CMAKEFILES(${distcheck_files})
|
||||
CMAKEFILES(CMakeLists.txt)
|
||||
BRLCAD_ADDEXEC(test_brep_ppx ppx.cpp "libbrep" NO_INSTALL)
|
||||
add_test(NAME brep_ppx COMMAND test_brep_ppx)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width: 8
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/* P P X . C P P
|
||||
* BRL-CAD
|
||||
*
|
||||
* Copyright (c) 2014 United States Government as represented by
|
||||
* the U.S. Army Research Laboratory.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; see the file named COPYING for more
|
||||
* information.
|
||||
*/
|
||||
/** @file ppx.cpp
|
||||
*
|
||||
* Point-point intersection tests.
|
||||
*
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "bu.h"
|
||||
#include "brep.h"
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "../brep_defines.h"
|
||||
|
||||
// Here we determine an upper limit on the magnitude of coordinate
|
||||
// values for test points.
|
||||
//
|
||||
// We need to be able to calculate point to point distance as:
|
||||
// sqrt((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2)
|
||||
//
|
||||
// To prevent overflow, we must restrict the coordinate values such
|
||||
// that:
|
||||
// (x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2 <= DBL_MAX
|
||||
//
|
||||
// If we want to choose an upper limit M on the magnitude of a
|
||||
// coordinate value to enforce this constraint, the restriction
|
||||
// simplifies to:
|
||||
// coord1, coord2 in [-M, M] s.t.
|
||||
// (coord2 - coord1)^2 <= DBL_MAX / 3.0
|
||||
// => (coord2 - coord1) <= sqrt(DBL_MAX / 3.0)
|
||||
//
|
||||
// Knowing that the maximum value of (coord2 - coord1) is 2M, we can
|
||||
// solve for M:
|
||||
// 2M <= sqrt(DBL_MAX / 3.0)
|
||||
// => M <= sqrt(DBL_MAX / 3.0) / 2.0
|
||||
//
|
||||
// We choose to use a value slightly less than the true DBL_MAX for
|
||||
// the calculation to avoid the possibility that floating point error
|
||||
// causes [3.0 * sqrt(DBL_MAX / 3.0)^2 <= DBL_MAX] to be false.
|
||||
static const double NEAR_DBL_MAX =
|
||||
std::numeric_limits<double>::max() -
|
||||
std::numeric_limits<double>::round_error();
|
||||
|
||||
static const double COORD_MAG_MAX = sqrt(NEAR_DBL_MAX / 3.0) / 2.0;
|
||||
|
||||
class PPX_Input {
|
||||
public:
|
||||
PPX_Input()
|
||||
: tol(0.0)
|
||||
{
|
||||
}
|
||||
ON_3dPoint ptA;
|
||||
ON_3dPoint ptB;
|
||||
ON_ClassArray<ON_PX_EVENT> events;
|
||||
bool default_tol;
|
||||
double tol;
|
||||
};
|
||||
|
||||
class PPX_Output {
|
||||
public:
|
||||
bool status;
|
||||
ON_ClassArray<ON_PX_EVENT> events;
|
||||
|
||||
bool Equals(std::string &log, const PPX_Output &other);
|
||||
};
|
||||
|
||||
static const double EVENT_EQUAL_TOL =
|
||||
std::numeric_limits<double>::round_error();
|
||||
|
||||
static bool
|
||||
point_events_equal(ON_PX_EVENT a, ON_PX_EVENT b)
|
||||
{
|
||||
if (a.m_type != b.m_type) {
|
||||
return false;
|
||||
}
|
||||
if (a.m_A.DistanceTo(b.m_A) >= EVENT_EQUAL_TOL) {
|
||||
return false;
|
||||
}
|
||||
if (a.m_B.DistanceTo(b.m_B) >= EVENT_EQUAL_TOL) {
|
||||
return false;
|
||||
}
|
||||
if (a.m_b.DistanceTo(b.m_b) >= EVENT_EQUAL_TOL) {
|
||||
return false;
|
||||
}
|
||||
if (a.m_Mid.DistanceTo(b.m_Mid) >= EVENT_EQUAL_TOL) {
|
||||
return false;
|
||||
}
|
||||
if (!ON_NearZero(a.m_radius - b.m_radius, EVENT_EQUAL_TOL)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PPX_Output::Equals(std::string &log, const PPX_Output &other)
|
||||
{
|
||||
bool ret = true;
|
||||
std::stringstream out;
|
||||
|
||||
if (status != other.status) {
|
||||
out << "return status: " << std::boolalpha << status << " vs " <<
|
||||
other.status << "\n";
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if (events.Count() != other.events.Count()) {
|
||||
out << "event count: " << events.Count() << " vs " <<
|
||||
other.events.Count() << "\n";
|
||||
ret = false;
|
||||
} else {
|
||||
for (int i = 0; i < events.Count(); ++i) {
|
||||
if (!point_events_equal(other.events[i], events[i])) {
|
||||
out << "event arrays don't match\n";
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log = out.str();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
test_intersection(PPX_Input in, PPX_Output expected_out)
|
||||
{
|
||||
PPX_Output out;
|
||||
|
||||
out.events = in.events;
|
||||
|
||||
if (in.default_tol) {
|
||||
out.status = ON_Intersect(in.ptA, in.ptB, out.events);
|
||||
} else {
|
||||
out.status = ON_Intersect(in.ptA, in.ptB, out.events, in.tol);
|
||||
}
|
||||
|
||||
std::string err_msg;
|
||||
if (!expected_out.Equals(err_msg, out)) {
|
||||
bu_exit(1, "Unexpected intersection result. Expected vs actual:\n%s",
|
||||
err_msg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static ON_PX_EVENT
|
||||
ppx_point_event(ON_3dPoint ptA, ON_3dPoint ptB)
|
||||
{
|
||||
ON_PX_EVENT event;
|
||||
event.m_type = ON_PX_EVENT::ppx_point;
|
||||
event.m_A = ptA;
|
||||
event.m_B = ptB;
|
||||
event.m_b = ON_2dPoint(0.0, 0.0);
|
||||
event.m_Mid = (ptA + ptB) * 0.5;
|
||||
event.m_radius = ptA.DistanceTo(ptB) * 0.5;
|
||||
return event;
|
||||
}
|
||||
|
||||
static void
|
||||
test_equal_points(ON_3dPoint pt)
|
||||
{
|
||||
ON_ClassArray<ON_PX_EVENT> events;
|
||||
events.Append(ppx_point_event(pt, pt));
|
||||
|
||||
PPX_Output expected_output;
|
||||
expected_output.status = true;
|
||||
expected_output.events = events;
|
||||
|
||||
PPX_Input input;
|
||||
input.ptA = input.ptB = pt;
|
||||
input.default_tol = true;
|
||||
|
||||
test_intersection(input, expected_output);
|
||||
}
|
||||
|
||||
static void
|
||||
do_equal_point_tests(void)
|
||||
{
|
||||
std::vector<double> coord_vals;
|
||||
coord_vals.push_back(-COORD_MAG_MAX);
|
||||
coord_vals.push_back(-INTERSECTION_TOL);
|
||||
coord_vals.push_back(0.0);
|
||||
coord_vals.push_back(INTERSECTION_TOL);
|
||||
coord_vals.push_back(COORD_MAG_MAX);
|
||||
|
||||
for (size_t i = 0; i < coord_vals.size(); ++i) {
|
||||
for (size_t j = 0; j < coord_vals.size(); ++j) {
|
||||
for (size_t k = 0; k < coord_vals.size(); ++k) {
|
||||
ON_3dPoint test_pt(coord_vals[i], coord_vals[j],
|
||||
coord_vals[k]);
|
||||
|
||||
test_equal_points(test_pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
do_equal_point_tests();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// tab-width: 8
|
||||
// mode: C++
|
||||
// c-basic-offset: 4
|
||||
// indent-tabs-mode: t
|
||||
// c-file-style: "stroustrup"
|
||||
// End:
|
||||
// ex: shiftwidth=4 tabstop=8
|
||||
@@ -1,12 +1,32 @@
|
||||
|
||||
set(DPLOT_READER dplot)
|
||||
|
||||
PERPLEX_TARGET(
|
||||
${DPLOT_READER}_scanner
|
||||
${DPLOT_READER}_scanner.perplex
|
||||
OUT_SRC_FILE ${DPLOT_READER}_scanner.c
|
||||
OUT_HDR_FILE ${DPLOT_READER}_scanner.h)
|
||||
LEMON_TARGET(
|
||||
${DPLOT_READER}_parser
|
||||
${DPLOT_READER}_parser.lemon
|
||||
OUT_SRC_FILE ${DPLOT_READER}_parser.c
|
||||
OUT_HDR_FILE ${DPLOT_READER}_parser.h)
|
||||
ADD_PERPLEX_LEMON_DEPENDENCY(${DPLOT_READER}_scanner ${DPLOT_READER}_parser)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${BRLCAD_BINARY_DIR}/include
|
||||
${BRLCAD_SOURCE_DIR}/include
|
||||
${BU_INCLUDE_DIRS}
|
||||
${GED_INCLUDE_DIRS}
|
||||
${PERPLEX_${DPLOT_READER}_scanner_INCLUDE_DIR}
|
||||
${LEMON_${DPLOT_READER}_parser_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
set(BREP_SRCS
|
||||
${PERPLEX_${DPLOT_READER}_scanner_SRC}
|
||||
${LEMON_${DPLOT_READER}_parser_SRC}
|
||||
dplot.c
|
||||
brep.cpp
|
||||
conversion.cpp
|
||||
csg.cpp
|
||||
|
||||
@@ -1480,9 +1480,11 @@ ged_brep_core(struct ged *gedp, int argc, const char *argv[])
|
||||
extern "C" {
|
||||
struct ged_cmd_impl brep_cmd_impl = { "brep", ged_brep_core, GED_CMD_DEFAULT };
|
||||
const struct ged_cmd brep_cmd = { &brep_cmd_impl };
|
||||
const struct ged_cmd *brep_cmds[] = { &brep_cmd, NULL };
|
||||
struct ged_cmd_impl dplot_cmd_impl = { "dplot", ged_dplot_core, GED_CMD_DEFAULT };
|
||||
const struct ged_cmd dplot_cmd = { &dplot_cmd_impl };
|
||||
const struct ged_cmd *brep_cmds[] = { &brep_cmd, &dplot_cmd, NULL };
|
||||
|
||||
static const struct ged_plugin pinfo = { GED_API, brep_cmds, 1 };
|
||||
static const struct ged_plugin pinfo = { GED_API, brep_cmds, 2 };
|
||||
|
||||
COMPILER_DLLEXPORT const struct ged_plugin *ged_plugin_info()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,799 @@
|
||||
/* D P L O T . C
|
||||
* BRL-CAD
|
||||
*
|
||||
* Copyright (c) 2014-2020 United States Government as represented by
|
||||
* the U.S. Army Research Laboratory.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; see the file named COPYING for more
|
||||
* information.
|
||||
*/
|
||||
/** @file dplot.c
|
||||
*
|
||||
* Brief description
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bu/color.h"
|
||||
#include "bu/opt.h"
|
||||
#include "raytrace.h"
|
||||
#include "rt/geom.h"
|
||||
#include "wdb.h"
|
||||
|
||||
#include "../ged_private.h"
|
||||
#include "./dplot_reader.h"
|
||||
|
||||
enum {
|
||||
DPLOT_INITIAL,
|
||||
DPLOT_SSX_FIRST,
|
||||
DPLOT_SSX,
|
||||
DPLOT_SSX_EVENTS,
|
||||
DPLOT_ISOCSX_FIRST,
|
||||
DPLOT_ISOCSX,
|
||||
DPLOT_ISOCSX_EVENTS,
|
||||
DPLOT_FACE_CURVES,
|
||||
DPLOT_LINKED_CURVES,
|
||||
DPLOT_SPLIT_FACES
|
||||
};
|
||||
|
||||
struct dplot_info {
|
||||
struct dplot_data fdata;
|
||||
int mode;
|
||||
struct ged *gedp;
|
||||
FILE *logfile;
|
||||
char *prefix;
|
||||
int ssx_idx;
|
||||
int isocsx_idx;
|
||||
int brep1_surf_idx;
|
||||
int brep2_surf_idx;
|
||||
int brep1_surf_count;
|
||||
int brep2_surf_count;
|
||||
int event_idx;
|
||||
int event_count;
|
||||
int brep1_isocsx_count;
|
||||
int isocsx_count;
|
||||
};
|
||||
|
||||
#define CLEANUP \
|
||||
fclose(info.logfile); \
|
||||
bu_free(info.prefix, "prefix"); \
|
||||
info.prefix = NULL; \
|
||||
if (info.fdata.ssx) bu_free(info.fdata.ssx, "ssx array");
|
||||
|
||||
#define RETURN_MORE \
|
||||
CLEANUP \
|
||||
return GED_MORE;
|
||||
|
||||
#define RETURN_ERROR \
|
||||
CLEANUP \
|
||||
info.mode = DPLOT_INITIAL; \
|
||||
return GED_ERROR;
|
||||
|
||||
HIDDEN int
|
||||
dplot_overlay(
|
||||
struct ged *gedp,
|
||||
const char *prefix,
|
||||
const char *infix,
|
||||
int idx,
|
||||
const char *name)
|
||||
{
|
||||
const char *cmd_av[] = {"overlay", "[filename]", "1.0", "[name]"};
|
||||
int ret, cmd_ac = sizeof(cmd_av) / sizeof(char *);
|
||||
struct bu_vls overlay_name = BU_VLS_INIT_ZERO;
|
||||
|
||||
bu_vls_printf(&overlay_name, "%s%s%d.plot3", prefix, infix, idx);
|
||||
cmd_av[1] = cmd_av[3] = bu_vls_cstr(&overlay_name);
|
||||
if (name) {
|
||||
cmd_av[3] = name;
|
||||
}
|
||||
ret = ged_overlay(gedp, cmd_ac, cmd_av);
|
||||
bu_vls_free(&overlay_name);
|
||||
|
||||
if (ret != GED_OK) {
|
||||
bu_vls_printf(gedp->ged_result_str, "error overlaying plot\n");
|
||||
return GED_ERROR;
|
||||
}
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
dplot_erase_overlay(
|
||||
struct dplot_info *info,
|
||||
const char *name)
|
||||
{
|
||||
const int NUM_EMPTY_PLOTS = 13;
|
||||
int i;
|
||||
|
||||
/* We can't actually erase the old plot without its real name,
|
||||
* which is unknown. Instead, we'll write a plot with the same
|
||||
* base name and color, which will overwrite the old one. We
|
||||
* don't actually know the color either, so we resort to writing
|
||||
* an empty plot with the given name using every color we created
|
||||
* plots with.
|
||||
*/
|
||||
for (i = 0; i < NUM_EMPTY_PLOTS; ++i) {
|
||||
int ret = dplot_overlay(info->gedp, info->prefix, "_empty", i, name);
|
||||
if (ret != GED_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
dplot_ssx(
|
||||
struct dplot_info *info)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
/* draw surfaces, skipping intersecting surfaces if in SSI mode */
|
||||
/* TODO: need to name these overlays so I can selectively erase them */
|
||||
for (i = 0; i < info->brep1_surf_count; ++i) {
|
||||
struct bu_vls name = BU_VLS_INIT_ZERO;
|
||||
bu_vls_printf(&name, "%s_brep1_surface%d", info->prefix, i);
|
||||
dplot_erase_overlay(info, bu_vls_cstr(&name));
|
||||
bu_vls_free(&name);
|
||||
}
|
||||
for (i = 0; i < info->brep2_surf_count; ++i) {
|
||||
struct bu_vls name = BU_VLS_INIT_ZERO;
|
||||
bu_vls_printf(&name, "%s_brep2_surface%d", info->prefix, i);
|
||||
dplot_erase_overlay(info, bu_vls_cstr(&name));
|
||||
bu_vls_free(&name);
|
||||
}
|
||||
if (info->mode == DPLOT_SSX_FIRST || info->mode == DPLOT_SSX || info->mode == DPLOT_SSX_EVENTS) {
|
||||
for (i = 0; i < info->brep1_surf_count; ++i) {
|
||||
if (info->mode != DPLOT_SSX_FIRST && i == info->brep1_surf_idx) {
|
||||
continue;
|
||||
}
|
||||
ret = dplot_overlay(info->gedp, info->prefix, "_brep1_surface", i, NULL);
|
||||
if (ret != GED_OK) {
|
||||
return GED_ERROR;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < info->brep2_surf_count; ++i) {
|
||||
if (info->mode != DPLOT_SSX_FIRST && i == info->brep2_surf_idx) {
|
||||
continue;
|
||||
}
|
||||
ret = dplot_overlay(info->gedp, info->prefix, "_brep2_surface", i, NULL);
|
||||
if (ret != GED_OK) {
|
||||
return GED_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* draw highlighted surface-surface intersection pair */
|
||||
if (info->mode == DPLOT_SSX || info->mode == DPLOT_SSX_EVENTS) {
|
||||
ret = dplot_overlay(info->gedp, info->prefix, "_highlight_brep1_surface",
|
||||
info->brep1_surf_idx, "dplot_ssx1");
|
||||
if (ret != GED_OK) {
|
||||
return GED_ERROR;
|
||||
}
|
||||
ret = dplot_overlay(info->gedp, info->prefix, "_highlight_brep2_surface",
|
||||
info->brep2_surf_idx, "dplot_ssx2");
|
||||
if (ret != GED_OK) {
|
||||
return GED_ERROR;
|
||||
}
|
||||
if (info->mode == DPLOT_SSX) {
|
||||
/* advance past the completed pair */
|
||||
++info->ssx_idx;
|
||||
}
|
||||
}
|
||||
if (info->mode == DPLOT_SSX_FIRST) {
|
||||
info->mode = DPLOT_SSX;
|
||||
}
|
||||
if (info->mode == DPLOT_SSX && info->ssx_idx < info->fdata.ssx_count) {
|
||||
bu_vls_printf(info->gedp->ged_result_str, "Press [Enter] to show surface-"
|
||||
"surface intersection %d", info->ssx_idx);
|
||||
return GED_MORE;
|
||||
}
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
void
|
||||
dplot_print_event_legend(struct dplot_info *info)
|
||||
{
|
||||
bu_vls_printf(info->gedp->ged_result_str, "yellow = transverse\n");
|
||||
bu_vls_printf(info->gedp->ged_result_str, "white = tangent\n");
|
||||
bu_vls_printf(info->gedp->ged_result_str, "green = overlap\n");
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
dplot_ssx_events(
|
||||
struct dplot_info *info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* erase old event plots */
|
||||
ret = dplot_erase_overlay(info, "curr_event");
|
||||
if (ret != GED_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (info->mode != DPLOT_SSX_EVENTS) {
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
if (info->event_count > 0) {
|
||||
/* convert event ssx_idx to string */
|
||||
struct bu_vls infix = BU_VLS_INIT_ZERO;
|
||||
bu_vls_printf(&infix, "_ssx%d_event", info->ssx_idx);
|
||||
|
||||
/* plot overlay */
|
||||
ret = dplot_overlay(info->gedp, info->prefix, bu_vls_cstr(&infix),
|
||||
info->event_idx, "curr_event");
|
||||
bu_vls_free(&infix);
|
||||
|
||||
if (ret != GED_OK) {
|
||||
return ret;
|
||||
}
|
||||
if (info->event_idx == 0) {
|
||||
dplot_print_event_legend(info);
|
||||
}
|
||||
}
|
||||
/* advance to next event, or return to initial state */
|
||||
if (++info->event_idx < info->event_count) {
|
||||
bu_vls_printf(info->gedp->ged_result_str, "Press [Enter] to show next event\n");
|
||||
return GED_MORE;
|
||||
}
|
||||
info->mode = DPLOT_INITIAL;
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
dplot_isocsx(
|
||||
struct dplot_info *info)
|
||||
{
|
||||
if (info->mode != DPLOT_ISOCSX &&
|
||||
info->mode != DPLOT_ISOCSX_FIRST &&
|
||||
info->mode != DPLOT_ISOCSX_EVENTS)
|
||||
{
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
if (info->fdata.ssx[info->ssx_idx].isocsx_events == NULL) {
|
||||
bu_vls_printf(info->gedp->ged_result_str, "The isocurves of neither "
|
||||
"surface intersected the opposing surface in surface-surface"
|
||||
" intersection %d.\n", info->ssx_idx);
|
||||
info->mode = DPLOT_INITIAL;
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
dplot_overlay(info->gedp, info->prefix, "_brep1_surface",
|
||||
info->brep1_surf_idx, "isocsx_b1");
|
||||
dplot_overlay(info->gedp, info->prefix, "_brep2_surface",
|
||||
info->brep2_surf_idx, "isocsx_b2");
|
||||
|
||||
if (info->mode == DPLOT_ISOCSX) {
|
||||
struct bu_vls infix = BU_VLS_INIT_ZERO;
|
||||
/* plot surface and the isocurve that intersects it */
|
||||
if (info->isocsx_idx < info->brep1_isocsx_count) {
|
||||
dplot_overlay(info->gedp, info->prefix, "_highlight_brep2_surface",
|
||||
info->brep2_surf_idx, "isocsx_b2");
|
||||
} else {
|
||||
dplot_overlay(info->gedp, info->prefix, "_highlight_brep1_surface",
|
||||
info->brep1_surf_idx, "isocsx_b1");
|
||||
}
|
||||
bu_vls_printf(&infix, "_highlight_ssx%d_isocurve", info->ssx_idx);
|
||||
dplot_overlay(info->gedp, info->prefix, bu_vls_cstr(&infix), info->isocsx_idx, "isocsx_isocurve");
|
||||
bu_vls_free(&infix);
|
||||
}
|
||||
|
||||
if (info->mode == DPLOT_ISOCSX_FIRST ||
|
||||
info->mode == DPLOT_ISOCSX)
|
||||
{
|
||||
if (info->mode == DPLOT_ISOCSX_FIRST ||
|
||||
++info->isocsx_idx < info->isocsx_count)
|
||||
{
|
||||
bu_vls_printf(info->gedp->ged_result_str, "Press [Enter] to show "
|
||||
"isocurve-surface intersection %d", info->isocsx_idx);
|
||||
info->mode = DPLOT_ISOCSX;
|
||||
return GED_MORE;
|
||||
} else {
|
||||
info->mode = DPLOT_INITIAL;
|
||||
}
|
||||
}
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
dplot_isocsx_events(struct dplot_info *info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (info->mode != DPLOT_ISOCSX_EVENTS) {
|
||||
return GED_OK;
|
||||
}
|
||||
ret = dplot_erase_overlay(info, "curr_event");
|
||||
if (ret != GED_OK) {
|
||||
return ret;
|
||||
}
|
||||
if (info->event_count > 0) {
|
||||
/* convert event ssx_idx to string */
|
||||
struct bu_vls infix = BU_VLS_INIT_ZERO;
|
||||
bu_vls_printf(&infix, "_ssx%d_isocsx%d_event", info->ssx_idx,
|
||||
info->isocsx_idx);
|
||||
|
||||
/* plot overlay */
|
||||
ret = dplot_overlay(info->gedp, info->prefix, bu_vls_cstr(&infix),
|
||||
info->event_idx, "curr_event");
|
||||
bu_vls_free(&infix);
|
||||
|
||||
if (ret != GED_OK) {
|
||||
bu_vls_printf(info->gedp->ged_result_str,
|
||||
"error overlaying plot\n");
|
||||
return ret;
|
||||
}
|
||||
if (info->event_idx == 0) {
|
||||
dplot_print_event_legend(info);
|
||||
}
|
||||
}
|
||||
/* advance to next event, or return to initial state */
|
||||
if (++info->event_idx < info->event_count) {
|
||||
bu_vls_printf(info->gedp->ged_result_str,
|
||||
"Press [Enter] to show next event\n");
|
||||
return GED_MORE;
|
||||
}
|
||||
|
||||
info->mode = DPLOT_INITIAL;
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
dplot_face_curves(struct dplot_info *info)
|
||||
{
|
||||
int f1_curves, f2_curves;
|
||||
if (info->mode != DPLOT_FACE_CURVES) {
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
f1_curves = info->fdata.ssx[info->ssx_idx].face1_clipped_curves;
|
||||
f2_curves = info->fdata.ssx[info->ssx_idx].face2_clipped_curves;
|
||||
info->event_count = f1_curves + f2_curves;
|
||||
|
||||
if (info->event_count == 0) {
|
||||
bu_vls_printf(info->gedp->ged_result_str, "No clipped curves for ssx"
|
||||
" pair %d.\n", info->ssx_idx);
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
if (info->event_idx < info->event_count) {
|
||||
struct bu_vls prefix;
|
||||
|
||||
dplot_overlay(info->gedp, info->prefix, "_brep1_surface",
|
||||
info->brep1_surf_idx, "face_b1");
|
||||
dplot_overlay(info->gedp, info->prefix, "_brep2_surface",
|
||||
info->brep2_surf_idx, "face_b2");
|
||||
|
||||
BU_VLS_INIT(&prefix);
|
||||
bu_vls_printf(&prefix, "%s_ssx%d", info->prefix, info->ssx_idx);
|
||||
dplot_erase_overlay(info, "clipped_fcurve");
|
||||
if (info->event_idx < f1_curves) {
|
||||
bu_vls_printf(&prefix, "_brep1face_clipped_curve");
|
||||
dplot_overlay(info->gedp, bu_vls_cstr(&prefix), "",
|
||||
info->event_idx, "clipped_fcurve");
|
||||
} else {
|
||||
bu_vls_printf(&prefix, "_brep2face_clipped_curve");
|
||||
dplot_overlay(info->gedp, bu_vls_cstr(&prefix), "",
|
||||
info->event_idx - f1_curves, "clipped_fcurve");
|
||||
}
|
||||
++info->event_idx;
|
||||
if (info->event_idx < info->event_count) {
|
||||
bu_vls_printf(info->gedp->ged_result_str, "Press [Enter] to show the"
|
||||
" next curve.");
|
||||
return GED_MORE;
|
||||
}
|
||||
}
|
||||
|
||||
info->mode = DPLOT_INITIAL;
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
dplot_split_faces(
|
||||
struct dplot_info *info)
|
||||
{
|
||||
int i, j;
|
||||
struct bu_vls name = BU_VLS_INIT_ZERO;
|
||||
struct bu_vls short_name = BU_VLS_INIT_ZERO;
|
||||
struct split_face split_face;
|
||||
|
||||
if (info->mode != DPLOT_SPLIT_FACES) {
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
if (info->event_idx >= info->fdata.split_face_count) {
|
||||
for (i = 0; i < info->fdata.split_face_count; ++i) {
|
||||
split_face = info->fdata.face[i];
|
||||
|
||||
bu_vls_trunc(&name, 0);
|
||||
bu_vls_printf(&name, "_split_face%d_outerloop_curve", i);
|
||||
for (j = 0; j < split_face.outerloop_curves; ++j) {
|
||||
bu_vls_trunc(&short_name, 0);
|
||||
bu_vls_printf(&short_name, "sf%do%d", i, j);
|
||||
dplot_overlay(info->gedp, info->prefix, bu_vls_cstr(&name), j,
|
||||
bu_vls_cstr(&short_name));
|
||||
}
|
||||
|
||||
bu_vls_trunc(&name, 0);
|
||||
bu_vls_printf(&name, "_split_face%d_innerloop_curve", i);
|
||||
for (j = 0; j < split_face.innerloop_curves; ++j) {
|
||||
bu_vls_trunc(&short_name, 0);
|
||||
bu_vls_printf(&short_name, "sf%di%d", i, j);
|
||||
dplot_overlay(info->gedp, info->prefix, bu_vls_cstr(&name), j,
|
||||
bu_vls_cstr(&short_name));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (info->event_idx > 0) {
|
||||
/* erase curves of previous split face */
|
||||
split_face = info->fdata.face[info->event_idx - 1];
|
||||
for (i = 0; i < split_face.outerloop_curves; ++i) {
|
||||
bu_vls_trunc(&short_name, 0);
|
||||
bu_vls_printf(&short_name, "sfo%d", i);
|
||||
dplot_erase_overlay(info, bu_vls_cstr(&short_name));
|
||||
}
|
||||
for (i = 0; i < split_face.innerloop_curves; ++i) {
|
||||
bu_vls_trunc(&short_name, 0);
|
||||
bu_vls_printf(&short_name, "sfi%d", i);
|
||||
dplot_erase_overlay(info, bu_vls_cstr(&short_name));
|
||||
}
|
||||
}
|
||||
|
||||
split_face = info->fdata.face[info->event_idx];
|
||||
bu_vls_printf(&name, "_split_face%d_outerloop_curve", info->event_idx);
|
||||
for (i = 0; i < info->fdata.face[info->event_idx].outerloop_curves; ++i) {
|
||||
bu_vls_trunc(&short_name, 0);
|
||||
bu_vls_printf(&short_name, "sfo%d", i);
|
||||
|
||||
dplot_erase_overlay(info, bu_vls_cstr(&short_name));
|
||||
dplot_overlay(info->gedp, info->prefix, bu_vls_cstr(&name), i,
|
||||
bu_vls_cstr(&short_name));
|
||||
}
|
||||
|
||||
bu_vls_trunc(&name, 0);
|
||||
bu_vls_printf(&name, "_split_face%d_innerloop_curve", info->event_idx);
|
||||
for (i = 0; i < info->fdata.face[info->event_idx].innerloop_curves; ++i) {
|
||||
bu_vls_trunc(&short_name, 0);
|
||||
bu_vls_printf(&short_name, "sfi%d", i);
|
||||
|
||||
dplot_erase_overlay(info, bu_vls_cstr(&short_name));
|
||||
dplot_overlay(info->gedp, info->prefix, bu_vls_cstr(&name), i,
|
||||
bu_vls_cstr(&short_name));
|
||||
}
|
||||
|
||||
bu_vls_printf(info->gedp->ged_result_str, "Press [Enter] to show "
|
||||
"split face %d", ++info->event_idx);
|
||||
return GED_MORE;
|
||||
}
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
dplot_linked_curves(
|
||||
struct dplot_info *info)
|
||||
{
|
||||
int i;
|
||||
if (info->mode != DPLOT_LINKED_CURVES) {
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
if (info->event_idx >= info->fdata.linked_curve_count) {
|
||||
for (i = 0; i < info->fdata.linked_curve_count; ++i) {
|
||||
dplot_overlay(info->gedp, info->prefix, "_linked_curve", i, NULL);
|
||||
}
|
||||
} else {
|
||||
dplot_overlay(info->gedp, info->prefix, "_linked_curve",
|
||||
info->event_idx, "linked_curve");
|
||||
bu_vls_printf(info->gedp->ged_result_str, "Press [Enter] to show "
|
||||
"linked curve %d", ++info->event_idx);
|
||||
return GED_MORE;
|
||||
}
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN void *
|
||||
dplot_malloc(size_t s) {
|
||||
return bu_malloc(s, "dplot_malloc");
|
||||
}
|
||||
|
||||
HIDDEN void
|
||||
dplot_free(void *p) {
|
||||
bu_free(p, "dplot_free");
|
||||
}
|
||||
|
||||
HIDDEN void
|
||||
dplot_load_file_data(struct dplot_info *info)
|
||||
{
|
||||
int i, j;
|
||||
struct ssx *curr_ssx;
|
||||
struct isocsx *curr_isocsx;
|
||||
int token_id;
|
||||
perplex_t scanner;
|
||||
void *parser;
|
||||
|
||||
/* initialize scanner and parser */
|
||||
parser = ParseAlloc(dplot_malloc);
|
||||
scanner = perplexFileScanner(info->logfile);
|
||||
|
||||
info->fdata.brep1_surface_count = info->fdata.brep2_surface_count = 0;
|
||||
info->fdata.ssx_count = 0;
|
||||
BU_LIST_INIT(&info->fdata.ssx_list);
|
||||
BU_LIST_INIT(&info->fdata.isocsx_list);
|
||||
perplexSetExtra(scanner, (void *)&info->fdata);
|
||||
|
||||
/* parse */
|
||||
while ((token_id = yylex(scanner)) != YYEOF) {
|
||||
Parse(parser, token_id, info->fdata.token_data, &info->fdata);
|
||||
}
|
||||
Parse(parser, 0, info->fdata.token_data, &info->fdata);
|
||||
|
||||
/* clean up */
|
||||
ParseFree(parser, dplot_free);
|
||||
perplexFree(scanner);
|
||||
|
||||
/* move ssx to dynamic array for easy access */
|
||||
info->fdata.ssx = NULL;
|
||||
if (info->fdata.ssx_count > 0) {
|
||||
|
||||
info->fdata.ssx = (struct ssx *)bu_malloc(
|
||||
sizeof(struct ssx) * info->fdata.ssx_count, "ssx array");
|
||||
|
||||
i = info->fdata.ssx_count - 1;
|
||||
while (BU_LIST_WHILE(curr_ssx, ssx, &info->fdata.ssx_list)) {
|
||||
BU_LIST_DEQUEUE(&curr_ssx->l);
|
||||
|
||||
curr_ssx->isocsx_events = NULL;
|
||||
if (curr_ssx->intersecting_isocurves > 0) {
|
||||
curr_ssx->isocsx_events = (int *)bu_malloc(sizeof(int) *
|
||||
curr_ssx->intersecting_isocurves, "isocsx array");
|
||||
|
||||
j = curr_ssx->intersecting_isocurves - 1;
|
||||
while (BU_LIST_WHILE(curr_isocsx, isocsx, &curr_ssx->isocsx_list)) {
|
||||
BU_LIST_DEQUEUE(&curr_isocsx->l);
|
||||
curr_ssx->isocsx_events[j--] = curr_isocsx->events;
|
||||
BU_PUT(curr_isocsx, struct isocsx);
|
||||
}
|
||||
}
|
||||
info->fdata.ssx[i--] = *curr_ssx;
|
||||
BU_PUT(curr_ssx, struct ssx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ged_dplot_core(struct ged *gedp, int argc, const char *argv[])
|
||||
{
|
||||
static struct dplot_info info;
|
||||
int ret;
|
||||
const char *filename, *cmd;
|
||||
char *dot;
|
||||
|
||||
info.gedp = gedp;
|
||||
bu_vls_trunc(gedp->ged_result_str, 0);
|
||||
|
||||
if (argc < 3) {
|
||||
bu_vls_printf(gedp->ged_result_str, "usage: %s logfile cmd\n",
|
||||
argv[0]);
|
||||
bu_vls_printf(gedp->ged_result_str, " where cmd is one of:\n");
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
" ssx (show intersecting surface pairs)\n");
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
" ssx N (show intersections of ssx pair N)\n");
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
" isocsx N (show intersecting isocurve-surface pairs of ssx pair N)\n");
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
" isocsx N M (show intersections of ssx pair N, isocsx pair M)\n");
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
" fcurves N (show clipped face curves of ssx pair N)\n");
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
" lcurves (show linked ssx curves used to split faces)\n");
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
" faces (show split faces used to construct result)\n");
|
||||
return GED_HELP;
|
||||
}
|
||||
filename = argv[1];
|
||||
cmd = argv[2];
|
||||
|
||||
if (info.mode == DPLOT_INITIAL) {
|
||||
if (BU_STR_EQUAL(cmd, "ssx") && argc == 3) {
|
||||
info.mode = DPLOT_SSX_FIRST;
|
||||
info.ssx_idx = 0;
|
||||
} else if (BU_STR_EQUAL(cmd, "ssx") && argc == 4) {
|
||||
/* parse surface pair index */
|
||||
const char *idx_str = argv[3];
|
||||
ret = bu_sscanf(idx_str, "%d", &info.ssx_idx);
|
||||
if (ret != 1) {
|
||||
bu_vls_printf(gedp->ged_result_str, "%s is not a valid "
|
||||
"surface pair (must be a non-negative integer)\n", idx_str);
|
||||
return GED_ERROR;
|
||||
}
|
||||
info.mode = DPLOT_SSX_EVENTS;
|
||||
info.event_idx = 0;
|
||||
} else if (BU_STR_EQUAL(cmd, "isocsx") && argc == 4) {
|
||||
const char *idx_str = argv[3];
|
||||
ret = bu_sscanf(idx_str, "%d", &info.ssx_idx);
|
||||
if (ret != 1) {
|
||||
bu_vls_printf(gedp->ged_result_str, "%s is not a valid "
|
||||
"surface pair (must be a non-negative integer)\n", idx_str);
|
||||
return GED_ERROR;
|
||||
}
|
||||
info.mode = DPLOT_ISOCSX_FIRST;
|
||||
info.isocsx_idx = 0;
|
||||
} else if (BU_STR_EQUAL(cmd, "isocsx") && argc == 5) {
|
||||
/* parse surface pair index */
|
||||
const char *idx_str = argv[3];
|
||||
ret = bu_sscanf(idx_str, "%d", &info.ssx_idx);
|
||||
if (ret != 1) {
|
||||
bu_vls_printf(gedp->ged_result_str, "%s is not a valid "
|
||||
"surface pair (must be a non-negative integer)\n", idx_str);
|
||||
return GED_ERROR;
|
||||
}
|
||||
idx_str = argv[4];
|
||||
ret = bu_sscanf(idx_str, "%d", &info.isocsx_idx);
|
||||
if (ret != 1) {
|
||||
bu_vls_printf(gedp->ged_result_str, "%s is not a valid "
|
||||
"isocurve-surface pair (must be a non-negative integer)\n", idx_str);
|
||||
return GED_ERROR;
|
||||
}
|
||||
info.mode = DPLOT_ISOCSX_EVENTS;
|
||||
info.event_idx = 0;
|
||||
} else if (BU_STR_EQUAL(cmd, "fcurves") && argc == 4) {
|
||||
const char *idx_str = argv[3];
|
||||
ret = bu_sscanf(idx_str, "%d", &info.ssx_idx);
|
||||
if (ret != 1) {
|
||||
bu_vls_printf(gedp->ged_result_str, "%s is not a valid "
|
||||
"surface pair (must be a non-negative integer)\n", idx_str);
|
||||
return GED_ERROR;
|
||||
}
|
||||
info.mode = DPLOT_FACE_CURVES;
|
||||
info.event_idx = 0;
|
||||
} else if (BU_STR_EQUAL(cmd, "lcurves") && argc == 3) {
|
||||
info.mode = DPLOT_LINKED_CURVES;
|
||||
info.event_idx = 0;
|
||||
} else if (BU_STR_EQUAL(cmd, "faces") && argc == 3) {
|
||||
info.mode = DPLOT_SPLIT_FACES;
|
||||
info.event_idx = 0;
|
||||
} else {
|
||||
bu_vls_printf(gedp->ged_result_str, "%s is not a recognized "
|
||||
"command or was given the wrong number of arguments\n",
|
||||
cmd);
|
||||
return GED_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* open dplot log file */
|
||||
info.logfile = fopen(filename, "r");
|
||||
if (!info.logfile) {
|
||||
bu_vls_printf(gedp->ged_result_str, "couldn't open log file \"%s\"\n", filename);
|
||||
return GED_ERROR;
|
||||
}
|
||||
|
||||
/* filename before '.' is assumed to be the prefix for all
|
||||
* plot-file names
|
||||
*/
|
||||
info.prefix = bu_strdup(filename);
|
||||
dot = strchr(info.prefix, '.');
|
||||
if (dot) {
|
||||
*dot = '\0';
|
||||
}
|
||||
|
||||
dplot_load_file_data(&info);
|
||||
|
||||
if (info.mode == DPLOT_SSX_FIRST ||
|
||||
info.mode == DPLOT_SSX ||
|
||||
info.mode == DPLOT_SSX_EVENTS ||
|
||||
info.mode == DPLOT_ISOCSX_FIRST ||
|
||||
info.mode == DPLOT_ISOCSX ||
|
||||
info.mode == DPLOT_ISOCSX_EVENTS)
|
||||
{
|
||||
if (info.fdata.ssx_count == 0) {
|
||||
bu_vls_printf(info.gedp->ged_result_str, "no surface surface"
|
||||
"intersections");
|
||||
RETURN_ERROR;
|
||||
} else if (info.ssx_idx < 0 ||
|
||||
info.ssx_idx > (info.fdata.ssx_count - 1))
|
||||
{
|
||||
bu_vls_printf(info.gedp->ged_result_str, "no surface pair %d (valid"
|
||||
" range is [0, %d])\n", info.ssx_idx, info.fdata.ssx_count - 1);
|
||||
RETURN_ERROR;
|
||||
}
|
||||
}
|
||||
if (info.fdata.ssx_count > 0) {
|
||||
info.brep1_surf_idx = info.fdata.ssx[info.ssx_idx].brep1_surface;
|
||||
info.brep2_surf_idx = info.fdata.ssx[info.ssx_idx].brep2_surface;
|
||||
info.event_count = info.fdata.ssx[info.ssx_idx].final_curve_events;
|
||||
info.brep1_isocsx_count =
|
||||
info.fdata.ssx[info.ssx_idx].intersecting_brep1_isocurves;
|
||||
info.isocsx_count =
|
||||
info.fdata.ssx[info.ssx_idx].intersecting_isocurves;
|
||||
}
|
||||
info.brep1_surf_count = info.fdata.brep1_surface_count;
|
||||
info.brep2_surf_count = info.fdata.brep2_surface_count;
|
||||
|
||||
if (info.mode == DPLOT_ISOCSX_EVENTS) {
|
||||
int *isocsx_events = info.fdata.ssx[info.ssx_idx].isocsx_events;
|
||||
|
||||
info.event_count = 0;
|
||||
if (isocsx_events) {
|
||||
info.event_count = isocsx_events[info.event_idx];
|
||||
}
|
||||
}
|
||||
|
||||
ret = dplot_ssx(&info);
|
||||
if (ret == GED_ERROR) {
|
||||
RETURN_ERROR;
|
||||
} else if (ret == GED_MORE) {
|
||||
RETURN_MORE;
|
||||
}
|
||||
|
||||
ret = dplot_ssx_events(&info);
|
||||
if (ret == GED_ERROR) {
|
||||
RETURN_ERROR;
|
||||
} else if (ret == GED_MORE) {
|
||||
RETURN_MORE;
|
||||
}
|
||||
|
||||
ret = dplot_isocsx(&info);
|
||||
if (ret == GED_ERROR) {
|
||||
RETURN_ERROR;
|
||||
} else if (ret == GED_MORE) {
|
||||
RETURN_MORE;
|
||||
}
|
||||
|
||||
ret = dplot_isocsx_events(&info);
|
||||
if (ret == GED_ERROR) {
|
||||
RETURN_ERROR;
|
||||
} else if (ret == GED_MORE) {
|
||||
RETURN_MORE;
|
||||
}
|
||||
|
||||
ret = dplot_face_curves(&info);
|
||||
if (ret == GED_ERROR) {
|
||||
RETURN_ERROR;
|
||||
} else if (ret == GED_MORE) {
|
||||
RETURN_MORE;
|
||||
}
|
||||
|
||||
ret = dplot_split_faces(&info);
|
||||
if (ret == GED_ERROR) {
|
||||
RETURN_ERROR;
|
||||
} else if (ret == GED_MORE) {
|
||||
RETURN_MORE;
|
||||
}
|
||||
|
||||
ret = dplot_linked_curves(&info);
|
||||
if (ret == GED_ERROR) {
|
||||
RETURN_ERROR;
|
||||
} else if (ret == GED_MORE) {
|
||||
RETURN_MORE;
|
||||
}
|
||||
|
||||
info.mode = DPLOT_INITIAL;
|
||||
CLEANUP;
|
||||
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* tab-width: 8
|
||||
* mode: C
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "stroustrup"
|
||||
* End:
|
||||
* ex: shiftwidth=4 tabstop=8
|
||||
*/
|
||||
@@ -0,0 +1,103 @@
|
||||
%include {
|
||||
#include "bu.h"
|
||||
#include <assert.h>
|
||||
#include "dplot_reader.h"
|
||||
}
|
||||
|
||||
%destructor statement_list {
|
||||
$$.n = data->ssx_count;
|
||||
}
|
||||
|
||||
%stack_overflow {
|
||||
fprintf(stderr, "Parser stack overflow. Last token was %d\n", yypMinor->yy0.n);
|
||||
}
|
||||
|
||||
%syntax_error {
|
||||
fprintf(stderr, "Syntax error. Last token (type %d) was %d. Ignoring "
|
||||
"input tokens until valid input is found.\n", yymajor, yyminor.yy0.n);
|
||||
}
|
||||
|
||||
%parse_failure {
|
||||
fprintf(stderr, "Parsing failed. Parser has reset.\n");
|
||||
}
|
||||
|
||||
%token_type {token_t}
|
||||
%extra_argument {struct dplot_data *data}
|
||||
|
||||
%token_prefix {TOKEN_}
|
||||
|
||||
%type count {int}
|
||||
%type index {int}
|
||||
|
||||
start_symbol ::= statement_list.
|
||||
|
||||
statement_list ::= /* empty */.
|
||||
statement_list ::= statement_list statement.
|
||||
|
||||
statement ::= surface_counts EOL.
|
||||
statement ::= ssx_info EOL.
|
||||
statement ::= linked_curve_count EOL.
|
||||
statement ::= split_face_count EOL.
|
||||
statement ::= split_face_info EOL.
|
||||
|
||||
surface_counts ::= SURFACES count(C1) count(C2). {
|
||||
data->brep1_surface_count = C1;
|
||||
data->brep2_surface_count = C2;
|
||||
}
|
||||
|
||||
ssx_info ::= SSX index(SURF_IDX1) index(SURF_IDX2) count(EVENTS) count(CRV_COUNT1) count(CRV_COUNT2) count(B1_ISO) count(ISO) isocsx_event_counts. {
|
||||
struct ssx *ssx;
|
||||
BU_GET(ssx, struct ssx);
|
||||
|
||||
ssx->brep1_surface = SURF_IDX1;
|
||||
ssx->brep2_surface = SURF_IDX2;
|
||||
ssx->final_curve_events = EVENTS;
|
||||
ssx->face1_clipped_curves = CRV_COUNT1;
|
||||
ssx->face2_clipped_curves = CRV_COUNT2;
|
||||
ssx->intersecting_brep1_isocurves = B1_ISO;
|
||||
ssx->intersecting_isocurves = ISO;
|
||||
BU_LIST_INIT(&ssx->isocsx_list);
|
||||
|
||||
/* move the list of event counts from the tmp location to this ssx
|
||||
* instance
|
||||
*/
|
||||
BU_LIST_APPEND_LIST(&ssx->isocsx_list, &data->isocsx_list);
|
||||
|
||||
BU_LIST_PUSH(&data->ssx_list, &ssx->l);
|
||||
++data->ssx_count;
|
||||
}
|
||||
|
||||
isocsx_event_counts ::= /* empty */.
|
||||
|
||||
isocsx_event_counts ::= isocsx_event_counts count(C). {
|
||||
struct isocsx *isocsx;
|
||||
BU_GET(isocsx, struct isocsx);
|
||||
|
||||
isocsx->events = C;
|
||||
BU_LIST_INIT(&isocsx->l);
|
||||
|
||||
BU_LIST_PUSH(&data->isocsx_list, &isocsx->l);
|
||||
}
|
||||
|
||||
linked_curve_count ::= LINKED_CURVES count(COUNT). {
|
||||
data->linked_curve_count = COUNT;
|
||||
}
|
||||
|
||||
split_face_count ::= SPLIT_FACES count(SPLIT_FACES). {
|
||||
data->split_face_count = SPLIT_FACES;
|
||||
data->face = (struct split_face *)bu_malloc(SPLIT_FACES *
|
||||
sizeof(struct split_face), "split face array");
|
||||
}
|
||||
|
||||
split_face_info ::= SPLIT_FACE index(I) count(OUTER_COUNT) count(INNER_COUNT). {
|
||||
data->face[I].outerloop_curves = OUTER_COUNT;
|
||||
data->face[I].innerloop_curves = INNER_COUNT;
|
||||
}
|
||||
|
||||
count(C) ::= NONNEGATIVE_INT(N). {
|
||||
C = N.n;
|
||||
}
|
||||
|
||||
index(I) ::= NONNEGATIVE_INT(N). {
|
||||
I = N.n;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dplot_reader.h"
|
||||
#include "bu.h"
|
||||
|
||||
HIDDEN void *
|
||||
dplot_malloc(size_t s) {
|
||||
return bu_malloc(s, "dplot_malloc");
|
||||
}
|
||||
|
||||
HIDDEN void
|
||||
dplot_free(void *p) {
|
||||
bu_free(p, "dplot_free");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, token_id;
|
||||
FILE *input_file;
|
||||
perplex_t scanner;
|
||||
void *parser;
|
||||
struct ssx *curr;
|
||||
struct dplot_data data;
|
||||
|
||||
if (argc != 2) {
|
||||
bu_exit(1, "usage: %s input\n", argv[0]);
|
||||
}
|
||||
|
||||
/* initialize scanner */
|
||||
input_file = fopen(argv[1], "r");
|
||||
if (!input_file) {
|
||||
bu_exit(2, "error: couldn't open \"%s\" for reading.\n", argv[1]);
|
||||
}
|
||||
scanner = perplexFileScanner(input_file);
|
||||
|
||||
data.ssx_count = 0;
|
||||
BU_LIST_INIT(&data.ssx_list);
|
||||
perplexSetExtra(scanner, (void *)&data);
|
||||
|
||||
/* initialize parser */
|
||||
parser = ParseAlloc(dplot_malloc);
|
||||
|
||||
/* parse */
|
||||
while ((token_id = yylex(scanner)) != YYEOF) {
|
||||
Parse(parser, token_id, data.token_data, &data);
|
||||
}
|
||||
Parse(parser, 0, data.token_data, &data);
|
||||
|
||||
/* move list data to array */
|
||||
if (data.ssx_count > 0) {
|
||||
data.ssx = (struct ssx *)bu_malloc(
|
||||
sizeof(struct ssx) * data.ssx_count, "ssx array");
|
||||
|
||||
i = data.ssx_count - 1;
|
||||
while (BU_LIST_WHILE(curr, ssx, &data.ssx_list)) {
|
||||
data.ssx[i--] = *curr;
|
||||
BU_LIST_DEQUEUE(&curr->l);
|
||||
BU_PUT(curr, struct ssx);
|
||||
}
|
||||
}
|
||||
|
||||
/* print data */
|
||||
bu_log("brep1: %d surfaces\n", data.brep1_surface_count);
|
||||
bu_log("brep2: %d surfaces\n", data.brep2_surface_count);
|
||||
|
||||
for (i = 0; i < data.ssx_count; ++i) {
|
||||
bu_log("%d curve events between surface 1-%d and 2-%d\n",
|
||||
data.ssx[i].final_curve_events, data.ssx[i].brep1_surface,
|
||||
data.ssx[i].brep2_surface);
|
||||
bu_log("\t%d brep1 isocurves intersected brep2\n",
|
||||
data.ssx[i].intersecting_brep1_isocurves);
|
||||
bu_log("\t%d brep2 isocurves intersected brep1\n",
|
||||
data.ssx[i].intersecting_isocurves -
|
||||
data.ssx[i].intersecting_brep1_isocurves);
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
if (data.ssx) {
|
||||
bu_free(data.ssx, "ssx array");
|
||||
}
|
||||
ParseFree(parser, dplot_free);
|
||||
perplexFree(scanner);
|
||||
fclose(input_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef DPLOT_PARSER
|
||||
#define DPLOT_PARSER
|
||||
|
||||
#define PERPLEX_ON_ENTER struct dplot_data *data = (struct dplot_data *)yyextra;
|
||||
|
||||
#include "bu.h"
|
||||
#include "dplot_parser.h"
|
||||
#include "dplot_scanner.h"
|
||||
|
||||
typedef struct {
|
||||
int n;
|
||||
} token_t;
|
||||
|
||||
struct isocsx {
|
||||
struct bu_list l;
|
||||
int events;
|
||||
};
|
||||
|
||||
struct ssx {
|
||||
struct bu_list l;
|
||||
int brep1_surface;
|
||||
int brep2_surface;
|
||||
int final_curve_events;
|
||||
int face1_clipped_curves;
|
||||
int face2_clipped_curves;
|
||||
int intersecting_brep1_isocurves;
|
||||
int intersecting_isocurves;
|
||||
struct bu_list isocsx_list; /* struct isocsx list */
|
||||
int *isocsx_events;
|
||||
};
|
||||
|
||||
struct split_face {
|
||||
int outerloop_curves;
|
||||
int innerloop_curves;
|
||||
};
|
||||
|
||||
struct dplot_data {
|
||||
token_t token_data;
|
||||
int brep1_surface_count;
|
||||
int brep2_surface_count;
|
||||
int linked_curve_count;
|
||||
int ssx_count;
|
||||
int split_face_count;
|
||||
struct bu_list ssx_list; /* struct ssx list */
|
||||
struct ssx *ssx;
|
||||
struct bu_list isocsx_list; /* struct ssx list */
|
||||
struct split_face *face;
|
||||
};
|
||||
|
||||
/* lemon prototypes */
|
||||
void *ParseAlloc(void *(*mallocProc)(size_t));
|
||||
void ParseFree(void *parser, void (*freeProc)(void *));
|
||||
void Parse(void *yyp, int yymajor, token_t tokenData, struct dplot_data *data);
|
||||
void ParseTrace(FILE *fp, char *s);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "bu.h"
|
||||
#include "dplot_reader.h"
|
||||
enum {INITIAL, normal};
|
||||
%%
|
||||
<> => normal { continue; }
|
||||
|
||||
<normal> {
|
||||
"surfaces" {
|
||||
return TOKEN_SURFACES;
|
||||
}
|
||||
|
||||
"ssx" {
|
||||
return TOKEN_SSX;
|
||||
}
|
||||
|
||||
"linkedcurves" {
|
||||
return TOKEN_LINKED_CURVES;
|
||||
}
|
||||
|
||||
"splitfaces" {
|
||||
return TOKEN_SPLIT_FACES;
|
||||
}
|
||||
|
||||
"splitface" {
|
||||
return TOKEN_SPLIT_FACE;
|
||||
}
|
||||
|
||||
[0-9]|[1-9][0-9]+ {
|
||||
data->token_data.n = 0;
|
||||
bu_sscanf(yytext, "%d", &data->token_data.n);
|
||||
return TOKEN_NONNEGATIVE_INT;
|
||||
}
|
||||
|
||||
[\n]+ {
|
||||
return TOKEN_EOL;
|
||||
}
|
||||
|
||||
[^] {
|
||||
/* ignore */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,8 @@ GED_EXPORT extern int brep_intersect_curve_curve(struct rt_db_internal *intern1,
|
||||
GED_EXPORT extern int brep_intersect_curve_surface(struct rt_db_internal *intern1, struct rt_db_internal *intern2, int i, int j);
|
||||
GED_EXPORT extern int brep_intersect_surface_surface(struct rt_db_internal *intern1, struct rt_db_internal *intern2, int i, int j, struct bn_vlblock *vbp);
|
||||
|
||||
GED_EXPORT extern int ged_dplot_core(struct ged *gedp, int argc, const char *argv[]);
|
||||
|
||||
using namespace brlcad;
|
||||
void
|
||||
plotface(const ON_BrepFace &face, struct bn_vlblock *vbp, int plotres, bool dim3d, const int red, const int green, const int blue);
|
||||
|
||||
@@ -127,6 +127,7 @@ GED_CMD(debugnmg)
|
||||
GED_CMD(decompose)
|
||||
GED_CMD(delay)
|
||||
GED_CMD(dir2ae)
|
||||
GED_CMD(dplot)
|
||||
GED_CMD(draw)
|
||||
GED_CMD(dsp)
|
||||
GED_CMD(dump)
|
||||
|
||||
@@ -13,6 +13,7 @@ CMAKEFILES(
|
||||
lint_tests.g
|
||||
obb_tests.g
|
||||
ged_tests.g
|
||||
pnts_in_out.g
|
||||
)
|
||||
|
||||
CMAKEFILES(CMakeLists.txt)
|
||||
|
||||
@@ -180,6 +180,12 @@ HIDDEN int to_data_vZ(struct ged *gedp,
|
||||
ged_func_ptr func,
|
||||
const char *usage,
|
||||
int maxargs);
|
||||
HIDDEN int to_dplot(struct ged *gedp,
|
||||
int argc,
|
||||
const char *argv[],
|
||||
ged_func_ptr func,
|
||||
const char *usage,
|
||||
int maxargs);
|
||||
HIDDEN int to_dlist_on(struct ged *gedp,
|
||||
int argc,
|
||||
const char *argv[],
|
||||
@@ -604,6 +610,7 @@ static struct to_cmdtab ged_cmds[] = {
|
||||
{"debugnmg", (char *)0, TO_UNLIMITED, to_pass_through_func, ged_debugnmg},
|
||||
{"decompose", (char *)0, TO_UNLIMITED, to_pass_through_func, ged_decompose},
|
||||
{"delay", (char *)0, TO_UNLIMITED, to_pass_through_func, ged_delay},
|
||||
{"dplot", "dplot_logfile", 1, to_dplot, ged_dplot},
|
||||
{"metaball_delete_pnt", (char *)0, TO_UNLIMITED, to_pass_through_func, ged_metaball_delete_pnt},
|
||||
{"pipe_delete_pnt", (char *)0, TO_UNLIMITED, to_pass_through_func, ged_pipe_delete_pnt},
|
||||
{"dir2ae", (char *)0, TO_UNLIMITED, to_pass_through_func, ged_dir2ae},
|
||||
@@ -3217,6 +3224,144 @@ to_dlist_on(struct ged *gedp,
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
to_dplot(struct ged *gedp,
|
||||
int argc,
|
||||
const char *argv[],
|
||||
ged_func_ptr func,
|
||||
const char *UNUSED(usage),
|
||||
int UNUSED(maxargs))
|
||||
{
|
||||
int ac;
|
||||
int ret;
|
||||
char *av[256];
|
||||
struct bu_vls callback_cmd = BU_VLS_INIT_ZERO;
|
||||
struct bu_vls temp = BU_VLS_INIT_ZERO;
|
||||
struct bu_vls result_copy = BU_VLS_INIT_ZERO;
|
||||
struct bview *gdvp;
|
||||
struct tclcad_ged_data *tgd = (struct tclcad_ged_data *)current_top->to_gedp->u_data;
|
||||
char *who_av[3] = {"who", "b", NULL};
|
||||
int first = 1;
|
||||
int aflag = 0;
|
||||
|
||||
/* copy all args */
|
||||
ac = argc;
|
||||
for (int i = 0; i < ac; ++i)
|
||||
av[i] = bu_strdup((char *)argv[i]);
|
||||
av[ac] = (char *)0;
|
||||
|
||||
/* check for displayed objects */
|
||||
ret = ged_who(gedp, 2, (const char **)who_av);
|
||||
if (ret == GED_OK && strlen(bu_vls_addr(gedp->ged_result_str)) == 0)
|
||||
aflag = 1;
|
||||
bu_vls_trunc(gedp->ged_result_str, 0);
|
||||
|
||||
while ((ret = (*func)(gedp, ac, (const char **)av)) & GED_MORE) {
|
||||
int ac_more;
|
||||
const char **avmp;
|
||||
const char **av_more = NULL;
|
||||
|
||||
/* save result string */
|
||||
bu_vls_substr(&result_copy, gedp->ged_result_str, 0, bu_vls_strlen(gedp->ged_result_str));
|
||||
bu_vls_trunc(gedp->ged_result_str, 0);
|
||||
|
||||
ret = ged_who(gedp, 1, (const char **)who_av);
|
||||
if (ret == GED_OK && strlen(bu_vls_addr(gedp->ged_result_str)) == 0)
|
||||
aflag = 1;
|
||||
|
||||
bu_vls_trunc(gedp->ged_result_str, 0);
|
||||
|
||||
for (size_t i = 0; i < BU_PTBL_LEN(¤t_top->to_gedp->ged_views); i++) {
|
||||
gdvp = (struct bview *)BU_PTBL_GET(¤t_top->to_gedp->ged_views, i);
|
||||
if (to_is_viewable(gdvp)) {
|
||||
gedp->ged_gvp->gv_x_samples = dm_get_width((struct dm *)gdvp->dmp);
|
||||
gedp->ged_gvp->gv_y_samples = dm_get_height((struct dm *)gdvp->dmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (first && aflag) {
|
||||
first = 0;
|
||||
to_autoview_all_views(current_top);
|
||||
} else {
|
||||
to_refresh_all_views(current_top);
|
||||
}
|
||||
/* restore result string */
|
||||
bu_vls_substr(gedp->ged_result_str, &result_copy, 0, bu_vls_strlen(&result_copy));
|
||||
bu_vls_free(&result_copy);
|
||||
|
||||
if (0 < bu_vls_strlen(&tgd->go_more_args_callback)) {
|
||||
bu_vls_trunc(&callback_cmd, 0);
|
||||
bu_vls_printf(&callback_cmd, "%s [string range {%s} 0 end]",
|
||||
bu_vls_addr(&tgd->go_more_args_callback),
|
||||
bu_vls_addr(gedp->ged_result_str));
|
||||
|
||||
if (Tcl_Eval(current_top->to_interp, bu_vls_addr(&callback_cmd)) != TCL_OK) {
|
||||
bu_vls_trunc(gedp->ged_result_str, 0);
|
||||
bu_vls_printf(gedp->ged_result_str, "%s", Tcl_GetStringResult(current_top->to_interp));
|
||||
Tcl_ResetResult(current_top->to_interp);
|
||||
return GED_ERROR;
|
||||
}
|
||||
|
||||
bu_vls_trunc(&temp, 0);
|
||||
bu_vls_printf(&temp, "%s", Tcl_GetStringResult(current_top->to_interp));
|
||||
Tcl_ResetResult(current_top->to_interp);
|
||||
} else {
|
||||
bu_log("\r%s", bu_vls_addr(gedp->ged_result_str));
|
||||
bu_vls_trunc(&temp, 0);
|
||||
if (bu_vls_gets(&temp, stdin) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Tcl_SplitList(current_top->to_interp, bu_vls_addr(&temp), &ac_more, &av_more) != TCL_OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ac_more < 1) {
|
||||
/* space has still been allocated */
|
||||
Tcl_Free((char *)av_more);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip first element if empty */
|
||||
avmp = av_more;
|
||||
if (*avmp[0] == '\0') {
|
||||
--ac_more;
|
||||
++avmp;
|
||||
}
|
||||
|
||||
/* ignore last element if empty */
|
||||
if (*avmp[ac_more-1] == '\0')
|
||||
--ac_more;
|
||||
|
||||
/* copy additional args */
|
||||
for (int i = 0; i < ac_more; ++i)
|
||||
av[ac++] = bu_strdup(avmp[i]);
|
||||
av[ac+1] = (char *)0;
|
||||
|
||||
Tcl_Free((char *)av_more);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < BU_PTBL_LEN(¤t_top->to_gedp->ged_views); i++) {
|
||||
gdvp = (struct bview *)BU_PTBL_GET(¤t_top->to_gedp->ged_views, i);
|
||||
if (to_is_viewable(gdvp)) {
|
||||
gedp->ged_gvp->gv_x_samples = dm_get_width((struct dm *)gdvp->dmp);
|
||||
gedp->ged_gvp->gv_y_samples = dm_get_height((struct dm *)gdvp->dmp);
|
||||
}
|
||||
}
|
||||
to_refresh_all_views(current_top);
|
||||
|
||||
bu_vls_free(&callback_cmd);
|
||||
bu_vls_free(&temp);
|
||||
|
||||
bu_vls_printf(gedp->ged_result_str, "BUILT_BY_MORE_ARGS");
|
||||
for (int i = 0; i < ac; ++i) {
|
||||
bu_vls_printf(gedp->ged_result_str, "%s ", av[i]);
|
||||
bu_free((void *)av[i], "to_more_args_func");
|
||||
}
|
||||
return GED_OK;
|
||||
}
|
||||
|
||||
HIDDEN int
|
||||
to_fontsize(struct ged *gedp,
|
||||
|
||||
@@ -212,6 +212,7 @@ package provide cadwidgets::Ged 1.0
|
||||
method delay {args}
|
||||
method dir2ae {args}
|
||||
method dlist_on {args}
|
||||
method dplot {args}
|
||||
method draw {args}
|
||||
method draw_ray {_start _partitions}
|
||||
method dsp {args}
|
||||
@@ -1636,6 +1637,10 @@ package provide cadwidgets::Ged 1.0
|
||||
eval $mGed dlist_on $args
|
||||
}
|
||||
|
||||
::itcl::body cadwidgets::Ged::dplot {args} {
|
||||
eval $mGed dplot $args
|
||||
}
|
||||
|
||||
::itcl::body cadwidgets::Ged::draw {args} {
|
||||
set mRayNeedGettrees 1
|
||||
|
||||
@@ -6259,6 +6264,7 @@ package provide cadwidgets::Ged 1.0
|
||||
$help add decompose {{nmg_solid [prefix]} {decompose nmg_solid into maximally connected shells}}
|
||||
$help add delay {{sec usec} {delay processing for the specified amount of time}}
|
||||
$help add dir2ae {{az el} {returns a direction vector given the azimuth and elevation}}
|
||||
$help add dplot {{dplot_log} {draws plotfiles from the given logfile}}
|
||||
$help add draw {{"-C#/#/# <objects>"} {draw objects}}
|
||||
$help add dsp {{obj [command]} {work with DSP primitives}}
|
||||
$help add dump {{file} {write current state of database object to file}}
|
||||
|
||||