Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31470287a1 | ||
|
|
342d8a9152 | ||
|
|
9e030edd60 | ||
|
|
b5bf1683a2 | ||
|
|
eb7e9cb38c | ||
|
|
84be85a74d | ||
|
|
3fd9ec8f4b | ||
|
|
7d2392d754 | ||
|
|
757bb76203 | ||
|
|
c70bab52c4 | ||
|
|
7929a747ad | ||
|
|
eac0f4d265 | ||
|
|
d6ae424de0 | ||
|
|
27ba3c4880 | ||
|
|
7ade8db130 | ||
|
|
e91023f354 | ||
|
|
303b90f7f1 | ||
|
|
875091f78a | ||
|
|
0716e4c842 | ||
|
|
ee6e1bebdc | ||
|
|
9d4f5bb124 | ||
|
|
21f442a4ad | ||
|
|
24d6f6f4cb | ||
|
|
d3e037a760 | ||
|
|
5a38423677 | ||
|
|
38113b1de7 | ||
|
|
fec9d07d43 | ||
|
|
4b09d6227f | ||
|
|
eab1e82de2 | ||
|
|
f7a8d5b406 | ||
|
|
85de3929e5 | ||
|
|
0a8c6d8bc2 | ||
|
|
a00efd15c6 | ||
|
|
06c8ab6204 | ||
|
|
cd55562c46 | ||
|
|
6d142b62e7 | ||
|
|
da2f503367 | ||
|
|
a9ac66788a | ||
|
|
4cc9f9cf01 | ||
|
|
7b1898d9fd | ||
|
|
e4d297893e | ||
|
|
0173dd8c40 | ||
|
|
cf344d773e | ||
|
|
8c51c1d527 | ||
|
|
6e48ea9ddd | ||
|
|
488f538040 | ||
|
|
17cc9f3a5a | ||
|
|
bf2c508826 | ||
|
|
f2e68b1a2a | ||
|
|
5e873e5081 | ||
|
|
3beed70eb8 | ||
|
|
73258d4264 | ||
|
|
8ae7482918 | ||
|
|
917ce5554c | ||
|
|
58ab0d5496 | ||
|
|
13b0699349 | ||
|
|
acd3a9800d | ||
|
|
03b36c1b61 | ||
|
|
b714d88185 | ||
|
|
eff3fea479 | ||
|
|
7358e90b54 | ||
|
|
3c2b0de9d2 | ||
|
|
a384f838fb | ||
|
|
1053594e9a | ||
|
|
72cde263cc | ||
|
|
b670a19aba | ||
|
|
2d9fa5c033 | ||
|
|
8be0f0ae85 | ||
|
|
00ffa4bd80 | ||
|
|
e5e0905d03 | ||
|
|
10d13793b0 | ||
|
|
70d5180438 | ||
|
|
50fe626694 | ||
|
|
ca403c92ed | ||
|
|
bab959474f | ||
|
|
27b522c155 | ||
|
|
875231c335 | ||
|
|
89810b06ca | ||
|
|
90e512b5d6 | ||
|
|
19fe382208 | ||
|
|
994c56b05f | ||
|
|
db76164ea8 | ||
|
|
58c5ed3681 | ||
|
|
05bd5c7470 | ||
|
|
2276f4ef8c | ||
|
|
188e72eb32 | ||
|
|
03306043ea | ||
|
|
28038fe0ea | ||
|
|
5b5cb8c538 | ||
|
|
1c20d18156 | ||
|
|
97920fbc90 | ||
|
|
37fb7d928a | ||
|
|
2056b359bd | ||
|
|
b4cf00292a | ||
|
|
6748dd37ab | ||
|
|
ef35c1dca1 | ||
|
|
8cdedd8752 | ||
|
|
e4ba0b166c | ||
|
|
586ac06c7e | ||
|
|
0d745fca35 | ||
|
|
5270e67abe | ||
|
|
14051845a3 | ||
|
|
d6fa937212 | ||
|
|
37aee260c1 | ||
|
|
56d64428ae | ||
|
|
0f6db7016d | ||
|
|
cbffc1171b | ||
|
|
21e034ee34 | ||
|
|
8f81f27d92 | ||
|
|
d729a7d3f2 | ||
|
|
17601916f4 | ||
|
|
90e5ede2b3 | ||
|
|
72454757ec | ||
|
|
6e9e1975b8 | ||
|
|
afedaa95bd | ||
|
|
5c8092b4e6 | ||
|
|
de09372b73 | ||
|
|
bcfb8669c1 | ||
|
|
066ec0bc8e | ||
|
|
fa3822b8f8 |
@@ -384,7 +384,7 @@ jobs:
|
||||
osx:
|
||||
name: macOS Clang
|
||||
needs: [linux]
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
strategy:
|
||||
fail-fast: true
|
||||
steps:
|
||||
@@ -403,7 +403,7 @@ jobs:
|
||||
- name: Prepare bext dependencies
|
||||
uses: ./brlcad/.github/actions/prepare-bext
|
||||
with:
|
||||
platform-channel: macos-14-${{ runner.arch }}-release
|
||||
platform-channel: macos-15-${{ runner.arch }}-release
|
||||
source-dir: ${{ github.workspace }}/brlcad
|
||||
output-dir: ${{ runner.temp }}/bext_output
|
||||
build-type: Release
|
||||
|
||||
@@ -177,7 +177,7 @@ jobs:
|
||||
osx_bext:
|
||||
name: macOS - BRL-CAD bext build
|
||||
needs: [linux_bext]
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
strategy:
|
||||
fail-fast: true
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
+36
-20
@@ -231,7 +231,7 @@ set(CMAKE_FIND_USE_PACKAGE_REGISTRY FALSE)
|
||||
# Prepare to manage and build BRL-CAD's external dependencies. Specifies a
|
||||
# specific commit hash to use in the 'bext' repository.
|
||||
include(BRLCAD_ExternalDeps)
|
||||
brlcad_bext_init(ea74d15dd9711eed1a985981059425f87e7396f1)
|
||||
brlcad_bext_init(42d8d7ca57f9d2f61192b41f0b41a731f1ba6c47)
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Define various utilities.
|
||||
@@ -352,9 +352,10 @@ set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||
# it should only be set to the installation value when actually installed.
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
|
||||
|
||||
# Add the automatically determined parts of the RPATH which point to
|
||||
# directories outside the build tree to the install RPATH
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
# Installed runtime paths are defined explicitly below. Do not append
|
||||
# directories discovered on the build host, since those paths may not exist
|
||||
# or may resolve to unrelated libraries on the installed system.
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
|
||||
|
||||
# The following logic is what allows binaries to run successfully in the build
|
||||
# directory AND install directory.
|
||||
@@ -678,8 +679,13 @@ endif(MSVC)
|
||||
# before use so platforms without GNU/LLVM-style linker options are skipped.
|
||||
brlcad_check_linker_flag(C "LINKER:--no-undefined" BRLCAD_LINKER_NO_UNDEFINED_C_FLAG_FOUND)
|
||||
brlcad_check_linker_flag(CXX "LINKER:--no-undefined" BRLCAD_LINKER_NO_UNDEFINED_CXX_FLAG_FOUND)
|
||||
if(BRLCAD_LINKER_NO_UNDEFINED_C_FLAG_FOUND AND BRLCAD_LINKER_NO_UNDEFINED_CXX_FLAG_FOUND)
|
||||
if(BRLCAD_LINKER_NO_UNDEFINED_C_FLAG_FOUND AND BRLCAD_LINKER_NO_UNDEFINED_CXX_FLAG_FOUND
|
||||
AND NOT BRLCAD_ENABLE_ADDRESS_SANITIZER)
|
||||
set(BRLCAD_LINKER_NO_UNDEFINED_FLAG "LINKER:--no-undefined" CACHE STRING "Linker flag requiring resolved shared library symbols" FORCE)
|
||||
else()
|
||||
# Clang links the AddressSanitizer runtime into executables, leaving its
|
||||
# shared-library instrumentation symbols unresolved until then.
|
||||
set(BRLCAD_LINKER_NO_UNDEFINED_FLAG "" CACHE STRING "Linker flag requiring resolved shared library symbols" FORCE)
|
||||
endif()
|
||||
brlcad_check_linker_flags(C BRLCAD_LINKER_WHOLE_ARCHIVE_GROUP_C_FLAG_FOUND "LINKER:--whole-archive" "LINKER:--no-whole-archive")
|
||||
brlcad_check_linker_flags(CXX BRLCAD_LINKER_WHOLE_ARCHIVE_GROUP_CXX_FLAG_FOUND "LINKER:--whole-archive" "LINKER:--no-whole-archive")
|
||||
@@ -1642,21 +1648,31 @@ if(NOT MSVC)
|
||||
endif(BRLCAD_WARNINGS OR BRLCAD_ENABLE_STRICT)
|
||||
|
||||
if(BRLCAD_ENABLE_COVERAGE)
|
||||
# TODO: These seem to GCC specific flags - should probably set up for clang
|
||||
# as well if that's our compiler...
|
||||
# https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
|
||||
# If we need different settings for different tools, should
|
||||
# encapsulate each tool's setup in a function
|
||||
check_c_flag(ftest-coverage)
|
||||
check_cxx_flag(ftest-coverage)
|
||||
if(FTEST_COVERAGE_C_FLAG_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage -fprofile-arcs -fprofile-update=atomic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs -fprofile-update=atomic")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lgcov -ftest-coverage -fprofile-arcs -fprofile-update=atomic")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov -ftest-coverage -fprofile-arcs -fprofile-update=atomic")
|
||||
else(FTEST_COVERAGE_C_FLAG_FOUND)
|
||||
message(SEND_ERROR "Building with coverage is not supported by BRL-CAD on this platform.")
|
||||
endif(FTEST_COVERAGE_C_FLAG_FOUND)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
check_c_flag(fprofile-instr-generate)
|
||||
check_cxx_flag(fprofile-instr-generate)
|
||||
check_c_flag(fcoverage-mapping)
|
||||
check_cxx_flag(fcoverage-mapping)
|
||||
if(NOT FPROFILE_INSTR_GENERATE_C_FLAG_FOUND OR
|
||||
NOT FPROFILE_INSTR_GENERATE_CXX_FLAG_FOUND OR
|
||||
NOT FCOVERAGE_MAPPING_C_FLAG_FOUND OR
|
||||
NOT FCOVERAGE_MAPPING_CXX_FLAG_FOUND)
|
||||
message(FATAL_ERROR "Clang source-based coverage is not supported by this toolchain.")
|
||||
endif()
|
||||
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
|
||||
add_link_options(-fprofile-instr-generate)
|
||||
else()
|
||||
check_c_flag(ftest-coverage)
|
||||
check_cxx_flag(ftest-coverage)
|
||||
if(FTEST_COVERAGE_C_FLAG_FOUND AND FTEST_COVERAGE_CXX_FLAG_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage -fprofile-arcs -fprofile-update=atomic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs -fprofile-update=atomic")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lgcov -ftest-coverage -fprofile-arcs -fprofile-update=atomic")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov -ftest-coverage -fprofile-arcs -fprofile-update=atomic")
|
||||
else()
|
||||
message(FATAL_ERROR "GCC coverage is not supported by this toolchain.")
|
||||
endif()
|
||||
endif()
|
||||
endif(BRLCAD_ENABLE_COVERAGE)
|
||||
|
||||
if(BRLCAD_ENABLE_STRICT)
|
||||
|
||||
@@ -151,10 +151,13 @@ recommended for serious developers.
|
||||
|
||||
Various useful configurations for working with bext:
|
||||
|
||||
* Get a git clone that has everything which might be needed (large,
|
||||
but useful for offline building)
|
||||
* Acquire bext and its dependencies from another repository host
|
||||
|
||||
git clone --recurse-submodules https://github.com/BRL-CAD/brlcad
|
||||
cmake .. -DBRLCAD_REPOSITORY_ROOT=https://git.example.org/brlcad
|
||||
|
||||
* Acquire bext and its dependencies from local bare Git mirrors
|
||||
|
||||
cmake .. "-DBRLCAD_REPOSITORY_ROOT=/path/to/mirror/BRL-CAD"
|
||||
|
||||
* Have prebuilt bext outputs to reuse - BRL-CAD will simply copy and prepare
|
||||
the pre-existing files
|
||||
@@ -398,10 +401,40 @@ Aliases: ENABLE_RUNTIME_DEBUG, ENABLE_RUN_TIME_DEBUG, ENABLE_RUNTIME_DEBUGGING
|
||||
ENABLE_RUN_TIME_DEBUGGING
|
||||
|
||||
|
||||
--- BRLCAD_REPOSITORY_ROOT ---
|
||||
|
||||
Repository URL or local directory containing bext and its dependency
|
||||
repositories. Defaults to https://github.com/BRL-CAD. The root directly
|
||||
contains repositories such as bext.git and astyle.git; BRL-CAD does not
|
||||
append BRL-CAD to the root.
|
||||
|
||||
Remote Git URLs (including SSH), native paths, and file:// URLs are supported.
|
||||
Relative native paths are resolved against the BRL-CAD source directory.
|
||||
Quote the entire -D argument for paths containing spaces. The setting is
|
||||
cached and is also passed as BEXT_REPOSITORY_ROOT when BRL-CAD configures
|
||||
bext, including when BRLCAD_EXT_SOURCE_DIR supplies an existing checkout.
|
||||
Alternate roots require bext sources with BEXT_REPOSITORY_ROOT support.
|
||||
|
||||
Local roots restrict CMake-driven Git acquisition and queries to file
|
||||
transport, with no online fallback. Mirrors must contain all required pinned
|
||||
commits and recursive submodules. Dependencies outside bext's canonical URL
|
||||
prefix require their own Git URL mappings. This setting does not restrict
|
||||
network access by dependency build scripts or change persistent Git settings.
|
||||
BRLCAD_EXT_DIR still selects prebuilt outputs, and changing the repository
|
||||
root alone does not force those outputs to be rebuilt.
|
||||
|
||||
To return to the default source:
|
||||
|
||||
cmake .. -DBRLCAD_REPOSITORY_ROOT=https://github.com/BRL-CAD
|
||||
|
||||
|
||||
--- BRLCAD_EXT_DIR ---
|
||||
|
||||
If specified, BRL-CAD will look in this directory for bext compiled outputs to
|
||||
bundle and use during the build.
|
||||
bundle and use during the build. Relative paths are resolved against the
|
||||
BRL-CAD source directory. Distcheck subconfigures reuse this resolved output
|
||||
directory and preserve BRLCAD_REPOSITORY_ROOT, BRLCAD_EXT_SOURCE_DIR, and
|
||||
BRLCAD_EXT_PARALLEL when specified.
|
||||
|
||||
|
||||
--- BRLCAD_EXT_SOURCE_DIR ---
|
||||
@@ -409,7 +442,8 @@ bundle and use during the build.
|
||||
If specified, BRL-CAD will look in this directory for bext source files. Use
|
||||
this when you have a pre-existing bext clone and don't want BRL-CAD's configure
|
||||
process to pull down another copy, but are still looking to have the BRL-CAD
|
||||
configure process manage producing bext build outputs.
|
||||
configure process manage producing bext build outputs. Relative paths are
|
||||
resolved against the BRL-CAD source directory.
|
||||
|
||||
|
||||
--- BRLCAD_EXT_PARALLEL ---
|
||||
|
||||
@@ -10,78 +10,107 @@ descriptive text that emphasizes or further describes significant
|
||||
changes made. See document footer for additional details.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--- 20XX-XX-XX Release 7.46.0 ---
|
||||
--- 2026-10-12 Release 7.46.0 ---
|
||||
----------------------------------------------------------------------
|
||||
|
||||
* updated MGED and Archer for Tcl 8.6.18 - Cliff Yapp
|
||||
This release expands geometry conversion and improves modeling
|
||||
reliability. STEP support adds AP203e2, AP214, and AP242
|
||||
import/export, native CSG round trips, and AP242 product and
|
||||
manufacturing information (PMI) import. IGES and JT conversion is
|
||||
expanded, and new OpenSCAD CSG import/export tools are available.
|
||||
|
||||
Facetization is more reliable, NMG solid ray tracing is 10-20 times
|
||||
faster, CSG ray tracing is faster, and BoT, DSP, and point-cloud ray
|
||||
intersections are corrected. MGED gains numerous fixes to primitive,
|
||||
sketch, and combination editing, drawing, dialogs, and preferences.
|
||||
|
||||
New tools support object nesting with arrange, building generation
|
||||
with mkbuilding, annotation editing, and primitive repair. Geometry
|
||||
analysis, image utilities, Windows support, documentation, and bundled
|
||||
dependencies also receive substantial updates.
|
||||
|
||||
* corrected Archer logic for saving window size - Cliff Yapp
|
||||
* fixed inside BoT rays, DSP surface normals, PNTS bounds - Cliff Yapp
|
||||
* improved mged fallback HTML manual viewer - Cliff Yapp
|
||||
* fixed gqa undefined densities and exit status - Chris McGregor
|
||||
* added ARBN support to the mged inside command - Cliff Yapp
|
||||
* improved HYP neck-ratio labels and BoT face selection - Cliff Yapp
|
||||
* fixed mged view panning, edit rotation, & ray queries - Cliff Yapp
|
||||
* preserved ARB, CLINE, TGC, & extrusion geometry edits - Cliff Yapp
|
||||
* restored mged command prompt focus at GUI startup - Cliff Yapp
|
||||
* improved pixscale & bwscale scaling and image piping - Sean Morrison
|
||||
* restored pixdiff behavior on .pix, added -b for .bw - Sean Morrison
|
||||
* improved facetize fallback methods and reliability - Cliff Yapp
|
||||
* updated mged and Archer for Tcl 8.6.18 and Itcl/Itk 4 - Cliff Yapp
|
||||
* fixed writes to fileless geometry databases - Cliff Yapp
|
||||
* fixed nastran-g handling of large property IDs - Rupesh, Cliff Yapp
|
||||
* fixed dxf-g invalid polyface index crashes - Meghna45-code, Cliff Yapp
|
||||
* fixed Archer primitive editors - Cliff Yapp
|
||||
* fixed Archer shutdown menu cleanup errors - Cliff Yapp
|
||||
* fixed MGED Build Pattern dialog - Cliff Yapp
|
||||
* fixed dxf-g invalid polyface idx crash - Meghna45-code, Cliff Yapp
|
||||
* fixed TclCAD framebuffer listing and deletion - Cliff Yapp
|
||||
* fixed MGED Build Pattern progress updates - Cliff Yapp
|
||||
* fixed MGED search -exec reentry and Ctrl-C crashes - Cliff Yapp
|
||||
* fixed MGED asynchronous commands and clone progress - Cliff Yapp
|
||||
* accelerated large and repeated MGED path drawing - Cliff Yapp
|
||||
* fixed mged Build Pattern progress updates - Cliff Yapp
|
||||
* fixed mged search -exec reentry and Ctrl-C crashes - Cliff Yapp
|
||||
* fixed mged asynchronous commands and clone progress - Cliff Yapp
|
||||
* accelerated large and repeated mged path drawing - Cliff Yapp
|
||||
* fixed ARB7 inside solid construction - Cliff Yapp
|
||||
* fixed direct ARB face and edge-direction editing - Cliff Yapp
|
||||
* fixed rtwizard startup with framebuffer contention - Cliff Yapp
|
||||
* fixed Archer annotation line display updates - Cliff Yapp
|
||||
* fixed Archer sketch scale drift in non-mm databases - Cliff Yapp
|
||||
* fixed toggle arrow callbacks during setup - Cliff Yapp
|
||||
* fixed Tcl dialogs with multi-word titles and messages - Cliff Yapp
|
||||
* fixed Tcl dialogs with multi-word titles and msgs - Cliff Yapp
|
||||
* fixed Archer Tank Wizard gun generation - Cliff Yapp
|
||||
* fixed MGED and Archer sketch arc tangency editing - Cliff Yapp
|
||||
* fixed mged and Archer sketch arc tangency editing - Cliff Yapp
|
||||
* fixed Archer ARB4 point 3 editing - Cliff Yapp
|
||||
* fixed ARB4 storage from make and mk_arb4 - Cliff Yapp
|
||||
* fixed ARB4 and ARB6 center point calculations - Cliff Yapp
|
||||
* fixed concurrent MGED and rtwizard framebuffer use - Cliff Yapp
|
||||
* fixed MGED ShotVis editing and reload failures - Cliff Yapp
|
||||
* fixed concurrent mged and rtwizard framebuffer use - Cliff Yapp
|
||||
* fixed mged ShotVis editing and reload failures - Cliff Yapp
|
||||
* fixed Tcl widget geometry and selection defects - Cliff Yapp
|
||||
* fixed MGED BoT editor property handling - Cliff Yapp
|
||||
* fixed MGED LOD dialog and adaptive BoT wireframes - Cliff Yapp
|
||||
* fixed MGED Plot, PostScript, and manual launch tools - Cliff Yapp
|
||||
* fixed MGED Overlap Tool multi-object result handling - Cliff Yapp
|
||||
* fixed mged BoT editor property handling - Cliff Yapp
|
||||
* fixed mged LOD dialog and adaptive BoT wireframes - Cliff Yapp
|
||||
* fixed mged Plot, PostScript, and manual launch tools - Cliff Yapp
|
||||
* fixed mged Overlap Tool multi-object result handling - Cliff Yapp
|
||||
* eliminated 16-fold redundant gchecker grid analysis - Cliff Yapp
|
||||
* fixed Archer tree handling for object names with spaces - Cliff Yapp
|
||||
* fixed submodel transforms & relative database paths - Sean Morrison
|
||||
* fixed Archer tree handling for names with spaces - Cliff Yapp
|
||||
* fixed RtWizard multi-object edge occlusion handling - Cliff Yapp
|
||||
* fixed RtWizard title, About, and preference handling - Cliff Yapp
|
||||
* fixed MGED startup file false legacy-syntax warnings - Cliff Yapp
|
||||
* fixed MGED saved-view deletion and collaboration sync - Cliff Yapp
|
||||
* fixed MGED font preferences apply and persistence - Cliff Yapp
|
||||
* fixed mged startup file false legacy-syntax warnings - Cliff Yapp
|
||||
* fixed mged saved-view deletion and collaboration sync - Cliff Yapp
|
||||
* fixed mged font preferences apply and persistence - Cliff Yapp
|
||||
* fixed Archer combination edits changing Boolean trees - Cliff Yapp
|
||||
* fixed Archer command-line help startup crash - Cliff Yapp
|
||||
* fixed MGED Geometry Browser menu and close behavior - Cliff Yapp
|
||||
* fixed MGED collaboration view unshare crash - Cliff Yapp
|
||||
* added an override for Archer's preference file location - Cliff Yapp
|
||||
* fixed mged Geometry Browser menu and close behavior - Cliff Yapp
|
||||
* fixed mged collaboration view unshare crash - Cliff Yapp
|
||||
* added override for Archer's preference file location - Cliff Yapp
|
||||
* fixed embedded Archer display and mode menus - Cliff Yapp
|
||||
* added Archer -h and --help command-line options - Cliff Yapp
|
||||
* fixed Archer Help opening the documentation menu - Sean Morrison
|
||||
* added arrange nest command for packing database objects - Sean Morrison
|
||||
* new mkbuilding tool for parametric/OSM/CityJSON models - Sean Morrison
|
||||
* added arrange nest command for packing db objects - Sean Morrison
|
||||
* added mkbuilding for parametric/OSM/CityJSON models - Sean Morrison
|
||||
* cross-platform BINUNIF and DSP byte-order handling - Sean Morrison
|
||||
* improved several cv default behaviors (s, 32, 64, n) - Sean Morrison
|
||||
* improved several cv default behaviors (s,32,64,n) - Sean Morrison
|
||||
* fixed invalid bot handling bug applying matrices - Sean Morrison
|
||||
* improved glTF import robustness via gcv - Sean Morrison
|
||||
* fixed bot dump glTF/GLB export; -F is now rejected - Cliff Yapp
|
||||
* faster NMG solid ray tracing (10-20x faster) - Sean Morrison
|
||||
* preserved primitive colors in shaded BoT and B-Rep drawing - Cliff Yapp
|
||||
* preserved B-Rep attributes through in-place geometry edits - Cliff Yapp
|
||||
* fixed gcv filter arguments containing one-character values - Cliff Yapp
|
||||
* preserved prim colors in shaded BoT and B-Rep drawing - Cliff Yapp
|
||||
* preserved B-Rep attrs through in-place geometry edits - Cliff Yapp
|
||||
* fixed gcv filter arguments w/ one-character values - Cliff Yapp
|
||||
* improved iges-g importer robustness - Cliff Yapp
|
||||
* expanded g-iges native CSG and B-Rep export support - Cliff Yapp
|
||||
* added IGES import and export support to gcv - Cliff Yapp
|
||||
* rt -b query option now supports a single value index - Sean Morrison
|
||||
* rt -b query option now supports a single value idx - Sean Morrison
|
||||
* fixed .dpix file format portability and icv support - Sean Morrison
|
||||
* expanded pixscale support for piped image data - Sean Morrison
|
||||
* fixed HYP volume and ARBN totals reported by analyze - Cliff Yapp
|
||||
* corrected rtarea sampling and exposed-area calculations - Cliff Yapp
|
||||
* fixed VOL data-file lookup and missing-data errors - Chris McGregor
|
||||
* corrected rtarea sampling/exposed-area calculations - Cliff Yapp
|
||||
* bot split now groups results and preserves mesh data - Cliff Yapp
|
||||
* bot decimate now preserves normals, UVs, and plate data - Cliff Yapp
|
||||
* bot decimate now preserves nrmls, UVs, and plate data - Cliff Yapp
|
||||
* added raytracing support for annotation objects - Cliff Yapp
|
||||
* fixed MGED X embedded framebuffer display manager crash - Cliff Yapp
|
||||
* fixed Windows subprocess quoting and empty arguments - Cliff Yapp
|
||||
* fixed mged X embedded framebuffer display manager crash - Cliff Yapp
|
||||
* fixed Windows drive-letter path handling - Cliff Yapp
|
||||
* added annotate command for managing annotation objects - Cliff Yapp
|
||||
* added repair command for supported invalid primitives - Cliff Yapp
|
||||
* changed default new-region material code from 1 to 0 - Keith Bowman
|
||||
@@ -103,26 +132,34 @@ changes made. See document footer for additional details.
|
||||
* added option validation to image & framebuffer tools - Sean Morrison
|
||||
* added contributor, API, command, & raytracing guides - Sean Morrison
|
||||
* added and updated command and library manual pages - Sean Morrison
|
||||
* added pnts write -f xyz export option - Chris McGregor
|
||||
* fixed mged ARB5 point editing - Cliff Yapp
|
||||
* fixed mged gqa and rtcheck stale overlap plots - Cliff Yapp
|
||||
* fixed procedural tree generator crashes - Sean Morrison, Cliff Yapp
|
||||
* added gaia Earth models with day/dusk/night textures - Sean Morrison
|
||||
* fixed fbcolor ramps & Windows input - Cliff Yapp, Sean Morrison
|
||||
* added parashot gravity trajectory path generator - Sean Morrison
|
||||
* added metaball point scaling (via metaball_move_pnt) - Sean Morrison
|
||||
* added metaball pnt scaling (via metaball_move_pnt) - Sean Morrison
|
||||
* all raytracing apps now report object prep failures - Sean Morrison
|
||||
* improved fast4-g robustness and error reporting - Cliff Yapp
|
||||
* improved robustness of g-vrml plate mode handling - Cliff Yapp
|
||||
* fixed MGED ARB5 point, pipe, and sketch editing - Cliff Yapp
|
||||
* added pnts write -f xyz export option - Chris McGregor
|
||||
* added support for tick drawing on MGED model axis - Cliff Yapp
|
||||
* added support for tick drawing on mged model axis - Cliff Yapp
|
||||
* added naca456 left and paired wing generation - Cliff Yapp
|
||||
* added patch-g -j option, specify object thicknesses - Sean Morrison
|
||||
* fixed fbcolor color ramp bug drawing the last color - Sean Morrison
|
||||
* corrected bwstat median and input error handling - Sean Morrison
|
||||
* fixed gist -Q quick preview option - Sean Morrison
|
||||
* rt preserves eye_pt setting in command scripts - Sean Morrison
|
||||
* removed trailing whitespace from nirt output - Sean Morrison
|
||||
* rt -l8 heat graphs now measure CPU time - Sean Morrison
|
||||
* documented gqa centroid & moments of inertia options - Sean Morrison
|
||||
* pixdiff now calculates pixel differences on bw files - Sean Morrison
|
||||
* fixed bwcrop single-axis crops and pixembed edge fill - Sean Morrison
|
||||
* fixed bwcrop single-axis crops & pixembed edge fill - Sean Morrison
|
||||
* fixed isize in non-mm databases - Josh Baker
|
||||
* fixed metaball adjust clearing points on errors - Sean Morrison
|
||||
* fixed benchmark+pixcmp correctness validation bug - Sean Morrison
|
||||
* fixed mged gqa option and value parsing - Sean Morrison
|
||||
* improved gist hierarchy overflow rendering - Chris McGregor
|
||||
* fixed rtxray -o grayscale/BW output - Sean Morrison
|
||||
* fbhelp writes help to stdout and rest to stderr - Sean Morrison
|
||||
* FB now supports /dev/stdout and /dev/stderr devices - Sean Morrison
|
||||
* fixed mged rt -C + -o background color to file bug - Sean Morrison
|
||||
@@ -131,7 +168,7 @@ changes made. See document footer for additional details.
|
||||
* added rtsil -o support for bw output - Sean Morrison
|
||||
* added cutting plane animation generation to rtwizard - Cliff Yapp
|
||||
* fixed pixdiff bug on Windows - Sean Morrison
|
||||
* fixed MGED startup window placement on Windows - Chris McGregor
|
||||
* fixed mged startup window placement on Windows - Chris McGregor
|
||||
* fixed pixborder utility right-side edge bug - Sean Morrison
|
||||
* fixed 'wavelet' image processing tool on Windows - Sean Morrison
|
||||
* quieted mged killtree spurious lookup failure output - Sean Morrison
|
||||
@@ -142,14 +179,16 @@ changes made. See document footer for additional details.
|
||||
* new doc guide, a visual overview of BRL-CAD objects - Sean Morrison
|
||||
* improved triangle quality produced by bot remesh - Cliff Yapp
|
||||
* updated numerous manpage command references - Josh Baker
|
||||
* fixed submodel paths relative to parent databases - Sean Morrison
|
||||
* improved performance making huge combinations - Sean Morrison
|
||||
* added PNTS get, adjust, form, & g2asc/asc2g support - Chris McGregor
|
||||
* fixed ANNOT get, adjust, & g2asc/asc2g support - Chris McGregor
|
||||
* added make -t primitive type listing - Chris McGregor
|
||||
* added gcv import conversion support for vrml/wrl 1.0 - Sean Morrison
|
||||
* fixed gcv appending to existing geometry databases - Sean Morrison
|
||||
* added CSS names, hex, HSL/HSV to libbu color parsing - Sean Morrison
|
||||
* improved OpenNURBS B-Rep import and adjustment safety - Cliff Yapp
|
||||
* improved Debian application menus and MIME associations - Jordi Sayol
|
||||
* improved Debian application menus/MIME associations - Jordi Sayol
|
||||
* updated Tcl/Tk dependency to v8.6.18 using bundled Itcl - Cliff Yapp
|
||||
* updated Clipper2 dependency to v1.5.4 - Cliff Yapp
|
||||
* updated Eigen dependency to v5.0.1 - Cliff Yapp
|
||||
* updated GDAL dependency to v3.13.3 - Cliff Yapp
|
||||
@@ -161,7 +200,6 @@ changes made. See document footer for additional details.
|
||||
* updated OpenNURBS dependency to v8.34.26223.11001 - Cliff Yapp
|
||||
* updated PROJ dependency to v9.8.1 - Cliff Yapp
|
||||
* updated PoissonRecon dependency to v18.75 - Cliff Yapp
|
||||
* updated Tcl/Tk dependency to v8.6.18, using bundled Itcl - Cliff Yapp
|
||||
* updated libjpeg-turbo dependency to v3.2.0 - Cliff Yapp
|
||||
* updated libosmesa dependency to SHA1 bfa90de - Cliff Yapp
|
||||
* updated libpng dependency to v1.6.58 - Cliff Yapp
|
||||
@@ -270,7 +308,7 @@ and extensively improving existing docs.
|
||||
* added metadata-aware image diff & nirt analysis - Cliff Yapp
|
||||
* added basic PNTS point-cloud ray tracing - Sean Morrison
|
||||
* improved nirt behavior in Windows bash consoles - Cliff Yapp
|
||||
* added g2asc/asc2g support for PNTS, DSP, and EBM - Sean Morrison
|
||||
* added g2asc/asc2g support for DSP and EBM - Sean Morrison
|
||||
* updated gct mesh decimation dependency to mmesh - Cliff Yapp
|
||||
* added procedural wing, propeller & tree generators - Cliff Yapp
|
||||
* added ISO tire dimensions & named tread presets - Cliff Yapp
|
||||
@@ -542,6 +580,7 @@ for more information.
|
||||
----------------------------------------------------------------------
|
||||
--- 2023-11-06 Release 7.38.0 ---
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This major release of BRL-CAD introduces significant improvements to
|
||||
the robustness of the facetize command by leveraging the Manifold
|
||||
library for boolean evaluation of meshes. Facetization is an operation
|
||||
@@ -580,6 +619,7 @@ processing high level assemblies in BRL-CAD's example geometry files:
|
||||
----------------------------------------------------------------------
|
||||
--- 2023-07-26 Release 7.36.0 ---
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This major release of BRL-CAD introduces significant updates to
|
||||
geometry conversion support. The update includes modernization for
|
||||
NURBS importing and interaction, BoT manipulation, and incorporates
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
BRL-CAD
|
||||
Release 7.44.2
|
||||
http://brlcad.org/
|
||||
BRL-CAD
|
||||
Release 7.46.0
|
||||
http://brlcad.org/
|
||||
|
||||
BRL-CAD is a powerful cross-platform open source combinatorial
|
||||
solid modeling system that includes an interactive 3D solid geometry
|
||||
|
||||
@@ -4,38 +4,54 @@
|
||||
:manmanual: BRL-CAD
|
||||
|
||||
== NAME
|
||||
pixdiff - highlight samples which differ between two pix or bw files
|
||||
pixdiff - highlight differences between two pix or bw images
|
||||
|
||||
== SYNOPSIS
|
||||
|
||||
[source]
|
||||
----
|
||||
pixdiff _file1.pix_ _file2.pix_ > _out.pix_
|
||||
pixdiff _file1.bw_ _file2.bw_ > _out.bw_
|
||||
pixdiff -b _file1.bw_ _file2.bw_ > _out.bw_
|
||||
----
|
||||
|
||||
|
||||
[[description]]
|
||||
== DESCRIPTION
|
||||
|
||||
*pixdiff* compares two raw *pix*(5) or *bw*(5) images byte by byte and
|
||||
writes a difference image of the same size to standard output. Bytes that
|
||||
differ by +/-1 are written at intensity 192, while larger differences are
|
||||
written at full intensity 255. Matching bytes are written at half their
|
||||
original intensity, providing visual context for locating differences.
|
||||
By default, *pixdiff* compares raw *pix*(5) images as RGB pixels and writes
|
||||
a PIX difference image to standard output. When all three channels of a
|
||||
pixel match, it writes a dim grayscale version of that pixel to all three
|
||||
output channels. When any channel differs, each matching channel is written
|
||||
as zero, each channel differing by one is written as 192, and each channel
|
||||
differing by more than one is written as 255.
|
||||
|
||||
Because the comparison does not interpret pixel structure, no format option
|
||||
is needed and *pixdiff* is independent of image resolution. The two inputs
|
||||
must be the same size in bytes; otherwise the program reports the mismatch
|
||||
and exits. Either input file may be given as
|
||||
With *-b*, *pixdiff* compares raw *bw*(5) images one byte at a time and
|
||||
writes a BW difference image. Differing samples use the same 192 and 255
|
||||
intensities; matching samples are written at half their original intensity.
|
||||
|
||||
No image dimensions are needed. The two inputs must be the same size in
|
||||
bytes, and PIX input must contain complete three-byte pixels. Otherwise,
|
||||
*pixdiff* reports an error. Either input file may be given as
|
||||
*-* to read from standard input. Output must be redirected; *pixdiff*
|
||||
refuses to write a raw image stream to a terminal.
|
||||
|
||||
Upon completion, the count of bytes that matched, that were off by 1, and
|
||||
that were off by many is reported on standard error.
|
||||
Upon completion, *pixdiff* reports matching, off-by-one, and larger-difference
|
||||
channel or sample counts on standard error.
|
||||
|
||||
Also see *bwdiff*(1), which can also operate on *pix*(5) files and can
|
||||
produce other kinds of difference output.
|
||||
*bwdiff -n -b* produces a similar BW highlight image, but writes 255 rather
|
||||
than 192 for off-by-one differences. The default *bwdiff*(1) output instead
|
||||
shows signed differences around a neutral gray.
|
||||
|
||||
|
||||
[[options]]
|
||||
== OPTIONS
|
||||
|
||||
*-b*::
|
||||
Treat both inputs and the output as one-byte-per-pixel BW images. Without
|
||||
this option, use three-byte-per-pixel PIX images.
|
||||
|
||||
*-h*::
|
||||
Show usage information.
|
||||
|
||||
|
||||
[[examples]]
|
||||
@@ -59,10 +75,10 @@ on standard error give a quick quantitative sense of how much changed.
|
||||
====
|
||||
[source,bash]
|
||||
----
|
||||
pixdiff depth_a.bw depth_b.bw > depth_diff.bw
|
||||
pixdiff -b depth_a.bw depth_b.bw > depth_diff.bw
|
||||
----
|
||||
Writes a grayscale highlight image using the same byte comparison and
|
||||
statistics as the color example; no format option is needed.
|
||||
Writes a grayscale highlight image using byte-wise comparison. Matching
|
||||
samples retain half their input intensity as context.
|
||||
====
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ Link with *-lanalyze*.
|
||||
The public interface is organized across the headers included by
|
||||
_analyze.h_, including _analyze/diff.h_, _analyze/density.h_,
|
||||
_analyze/grid.h_, _analyze/heal.h_, _analyze/info.h_, _analyze/pnts.h_,
|
||||
_analyze/polygonize.h_, _analyze/nirt.h_, _analyze/voxelize.h_, and
|
||||
_analyze/contour.h_, _analyze/polygonize.h_, _analyze/nirt.h_,
|
||||
_analyze/voxelize.h_, and
|
||||
_analyze/worker.h_.
|
||||
|
||||
== DESCRIPTION
|
||||
@@ -32,7 +33,7 @@ to gather the information they need.
|
||||
Facilities provided by the library include model differencing, material
|
||||
density and mass property analysis, ray-based gridding and sampling,
|
||||
geometry healing, model information queries, point-cloud generation and
|
||||
processing, polygonization and voxelization of geometry, and the
|
||||
processing, manifold dual contouring and voxelization of geometry, and the
|
||||
interactive ray-tracing engine used by the *nirt*(1) command. A parallel
|
||||
worker interface supports distributing analysis work across multiple
|
||||
threads.
|
||||
|
||||
@@ -200,6 +200,56 @@ ____
|
||||
|
||||
The LIBRT_DEBUG environment variable may be set to the hexadecimal bit vector as described by the DEBUG_* flags listed in the raytrace.h header. Similarly, many LIBRT applications provide a "-x #" command-line option which will take precedence over the environment variable.
|
||||
|
||||
The RT_DEBUG_RTCMP flag (0x10000000) (set with LIBRT_DEBUG=10000000)
|
||||
sets up rtcmp capture, but recording starts disabled. Set
|
||||
LIBRT_RTCMP_FILE before enabling the flag, then call
|
||||
rt_rtcmp_capture_set_enabled(1) from the application or a debugger to
|
||||
record selected rays. Call rt_rtcmp_capture_set_enabled(0) to stop
|
||||
recording. Enabling returns -1 if the debug flag is unset or the output
|
||||
writer failed to initialize; disabling returns 0 even before setup. A
|
||||
ray must begin while recording is enabled, and leaving recording
|
||||
disabled when it finishes suppresses its record. The debug flag must be
|
||||
set before concurrent ray shooting; use the setter to change recording
|
||||
state while rays are running.
|
||||
|
||||
Captured hits append one high-precision rtcmp JSON record per ray with
|
||||
final partitions. Misses produce no record. librt never clears the
|
||||
output file; the caller must clear or rotate it before a new comparison
|
||||
as needed. Separate processes must not write to the same file
|
||||
concurrently. Pending records are flushed within two seconds under
|
||||
normal operation and during normal process shutdown; call
|
||||
rt_rtcmp_capture_flush() to wait for pending records when using a
|
||||
debugger. Disabling recording does not discard records already queued. A
|
||||
process terminated abnormally may lose pending records. rtcmp comparison
|
||||
files should use the same hit-only capture mode on both sides; its
|
||||
generation mode also includes misses. The output can be expanded to also
|
||||
include primitive segments if LIBRT_RTCMP_PRIMITIVES is set to 1 before
|
||||
capture is set up.
|
||||
|
||||
For example, run a single-threaded ray tracing application in a debugger
|
||||
and stop at `rt_shootray` for the suspect ray. Capture just that call,
|
||||
then compare it with a capture of the same ray from a reference build:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
$ LIBRT_DEBUG=10000000 LIBRT_RTCMP_FILE=trial.json \
|
||||
gdb --args ./ray_application model.g
|
||||
(gdb) break rt_shootray
|
||||
(gdb) run
|
||||
(gdb) call rt_rtcmp_capture_set_enabled(1)
|
||||
(gdb) finish
|
||||
(gdb) call rt_rtcmp_capture_set_enabled(0)
|
||||
(gdb) call rt_rtcmp_capture_flush()
|
||||
(gdb) quit
|
||||
$ rtcmp -c reference.json trial.json
|
||||
----
|
||||
|
||||
Continue to the suspect ray before enabling capture if the breakpoint
|
||||
first stops on another ray. Produce `reference.json` with the same ray
|
||||
and the same capture mode; set LIBRT_RTCMP_PRIMITIVES=1 for both runs
|
||||
when primitive segments are needed to locate a difference before Boolean
|
||||
evaluation.
|
||||
|
||||
The LIBRT_V4FLIP environment variable may be set to a true or false value to respectively force or disable endianness interpretation of v4 geometry database files. The default behavior is to automatically detect whether flipping the endian interpretation will help LIBRT read a binary-incompatible v4 geometry database file. Setting LIBRT_V4FLIP will override automatic detection.
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ facetize - Creates __new_object__ using __old_object__ as a guide, creating an e
|
||||
|
||||
[source]
|
||||
----
|
||||
facetize [-h] [-v] [-q] [-n] [-r] [-s suffix] [-p prefix] [--in-place] [--max-time #] [--max-pnts #] [--resume] [--methods m1,m2,...] [--method-opts METHOD opt1=val opt2=val...] [--no-empty] [--log-file filename] [--nmg-booleval] [--disable-fixup] [--perturb] [--no-perturb] [--perturb-sa-tol #] [--perturb-vol-tol #] [--tolerate-failures] [-B -t threshold] {old_object new_object}
|
||||
facetize [-h] [-v] [-q] [-n] [-r] [-j jobs] [-s suffix] [-p prefix] [--in-place] [--max-time #] [--max-pnts #] [--resume] [--methods m1,m2,...] [--method-opts METHOD opt1=val opt2=val...] [--no-empty] [--log-file filename] [--nmg-booleval] [--disable-fixup] [--perturb] [--no-perturb] [--perturb-sa-tol #] [--perturb-vol-tol #] [--tolerate-failures] [-B -t threshold] {old_object new_object}
|
||||
----
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ By default, the Manifold BoT path can make use of a coplanarity-avoidance pertur
|
||||
|
||||
When the perturbation step is active, per-region *facetize* validates the initial Boolean output against the original CSG geometry using a Crofton stochastic raytrace. The default tolerance thresholds that trigger a perturb retry are 10% for both surface area and volume; these can be adjusted with *--perturb-sa-tol* and *--perturb-vol-tol*. At the end of a per-region facetization run *facetize* prints a concise validation summary listing how many regions passed, triggered a perturb retry, or encountered one of the following noteworthy conditions:
|
||||
|
||||
_Unbounded halfspace (validation unavailable)_: Crofton surface-area and volume comparisons require a finite sampling domain. A standalone halfspace, or another CSG result without finite bounds, is therefore not sampled and is counted as having validation unavailable. A bounded object intersected with or subtracted by a halfspace can still be validated because its finite operand supplies the sampling bounds.
|
||||
|
||||
_Sub-mm / few-hit bypass (accepted with note)_: When the Crofton sampler finds only a very small number of ray-surface intersections (below an internal threshold of 50 crossings), the sampling noise alone would exceed 14% relative error, making any SA comparison meaningless. Geometry in this category is typically sub-millimetre in cross-section (e.g., a TGC with a radius under 0.2 mm) but the stochastic sampler has confirmed that some geometry is present. The BoT conversion is accepted and the region is counted separately in the summary. Users should verify that such extreme geometry reflects actual modeling intent rather than an accidental near-degenerate primitive.
|
||||
|
||||
_Zero-hit replacement_: When the Crofton sampler fires rays but records zero intersections with the CSG geometry while the corresponding BoT is non-empty, *facetize* concludes that the Boolean evaluation most likely produces empty geometry (for example, a subtractor that fully engulfs the base object). In this case the non-empty BoT is discarded and replaced with an empty BoT to match the expected raytrace behavior. If this replacement appears unexpected for a given region, the *lint* command can be used to inspect the result.
|
||||
@@ -61,13 +63,21 @@ Different tolerance settings will create finer or coarser meshes. See the *tol*
|
||||
|
||||
Primitive tessellation is performed in a child process against a private working copy of the database in the BRL-CAD cache. The original database is not modified as individual primitive meshes are generated. Only after the conversion succeeds are the requested results transferred from the working database. This separation also permits an interrupted conversion to retain its intermediate state for use with *--resume*.
|
||||
|
||||
The parent command sends primitive names to a persistent tessellation process one at a time. The child reports a result for each name, so a timeout, conversion failure, or child-process crash that occurs before a database write can be associated directly with the affected primitive. The child is restarted when necessary and processing continues with the next name; the parent does not subdivide and retry the whole group to discover which object failed. Unless output is suppressed with *--quiet*, long tessellation batches also report their current object and completed-object count at approximately five-second intervals.
|
||||
The parent command sends primitive names to a small pool of persistent tessellation processes. Each child reports a result for every name, so a timeout, conversion failure, or child-process crash can be associated directly with the affected primitive. A child is restarted when necessary and processing continues with the next name; the parent does not subdivide and retry the whole group to discover which object failed. Unless output is suppressed with *--quiet*, long tessellation batches also report their completed-object count and active-worker state at approximately five-second intervals.
|
||||
|
||||
Database updates use a separate write handshake. After preparing a mesh in memory, the child announces that it is ready to write and reports the approximate mesh size, then waits. The parent acknowledges that it is waiting for the write before the child may update the working database. The child explicitly reports when the update is complete. Consequently, the normal per-object tessellation limit, including *--max-time* and method-specific limits, applies to mesh preparation and does not interrupt an acknowledged database write.
|
||||
By default, *facetize* uses at most two worker processes and only enables the second when both CPU and memory information indicate it is safe. It reserves the larger of one GiB or one quarter of total physical memory for the rest of the system. Starting another job also requires at least 512 MiB beyond that reserve, or the largest worker resident-memory measurement seen so far if that is greater. If the platform cannot report the required memory information, *facetize* falls back to one worker. The available CPU count is divided among worker processes and is also imposed as the thread limit inside each worker, preventing nested algorithms from independently using all CPUs. *--jobs* changes the maximum process count; it does not bypass the memory admission checks.
|
||||
|
||||
Per-region BoT conversion uses this worker policy for both independent CSG validation and initial Manifold Boolean evaluation. When more than one worker is available, persistent validation processes each open their own read-only handle to the original database and compute Crofton surface-area and volume references for different regions. Persistent Boolean processes then evaluate different region trees using independent read-only handles to one shared snapshot of the tessellated working database. That snapshot also serves as the rollback checkpoint, so increasing *--jobs* does not create additional full database copies. This process isolation avoids sharing mutable raytrace preparation or database state between concurrent evaluations. Each result remains associated with the requested region name. The parent commits completed BoTs through one writer and continues to perform hierarchy changes, validation decisions, and any perturb retries serially. A one-worker run retains the established in-process order and avoids the snapshot phase.
|
||||
|
||||
Validation and Boolean workers report their completed-region count and active-worker state approximately every five seconds. When *--max-time* is specified, it also bounds each parallel CSG reference or Boolean request; a timed-out process is terminated, and the failure is associated with that region. Failure or timeout of supplementary CSG validation does not cause unrelated regions to be retried.
|
||||
|
||||
Database updates use a separate write handshake. After preparing a mesh in memory, a child announces that it is ready to write and reports the approximate mesh size and its current resident memory, then waits. The parent grants write permission, the child acknowledges when it is starting the write, and the child explicitly reports when the update is complete. Consequently, the normal per-object tessellation limit, including *--max-time* and method-specific limits, applies to mesh preparation and does not interrupt an acknowledged write.
|
||||
|
||||
With multiple workers, primitive tessellation children write to small staging databases rather than modifying the shared working database. Region Boolean children read one immutable cache-local snapshot while completed results are committed to the working database. The snapshot doubles as the recovery checkpoint and is opened independently by each worker; it is not duplicated per worker. For very large files, snapshot preparation reports the amount copied and elapsed time at five-second intervals. A region result is first completed in memory and enters the write handshake only when it is ready to replace the prior staged result. After a child reports a completed staging write, the parent submits that result to a single persistent writer process. The writer announces that it is ready, waits for the parent's permission, acknowledges that it is starting the write, transfers the result through one persistent working-database handle, and reports completion. This permits tessellation and initial region Boolean evaluation to proceed in parallel without concurrent database allocation updates or repeated full directory scans, while allowing the parent to supervise the canonical database write itself. With one worker, the established direct path avoids the extra staging I/O and database snapshot.
|
||||
|
||||
Before the first primitive conversion, the parent measures write throughput on the same cache filesystem as the working database. It writes a temporary file in 1 MiB chunks until approximately one second has elapsed or 128 MiB has been written, then removes the file immediately. Successful mesh writes of at least 1 MiB subsequently refine this profile. For each database update, the parent allows ten times the projected write time, with a minimum of five seconds and a maximum of five minutes. This measured allowance protects legitimate long writes on slow storage while still detecting a genuinely stalled update.
|
||||
|
||||
If a child fails before write permission is granted, the working database is known to be unchanged and no rollback is needed. A failure, crash, or write-deadline expiration after permission is granted but before completion is ambiguous: the working database may contain a partial update. In that case *facetize* restores its cache-local checkpoint and replays only the primitive conversions already known to have succeeded. The original database remains untouched during this recovery.
|
||||
If a child fails before acknowledging that its write has started, the working database is known to be unchanged and no rollback is needed. In parallel mode, a failure during a child write affects only that worker's disposable staging database, so the failed object is reported and the worker can be restarted without replaying unrelated objects. A serial child failure during a direct write, or a writer-process failure after acknowledging write start, is ambiguous because the working database may contain a partial update. In those cases *facetize* restores its cache-local checkpoint and replays only the conversions not already tied to a specific failure. The original database remains untouched during this recovery.
|
||||
|
||||
|
||||
[[facetize_options]]
|
||||
@@ -94,6 +104,10 @@ Instructs *facetize* to produce NMG solids rather than BoT solids.
|
||||
Rather than converting all specified inputs to one top level object, walk specified trees and individually convert regions to facetized objects. This mode is useful when wanting to display models in shaded mode while preserving color and region ID properties. If no regions are present a normal conversion is performed instead.
|
||||
|
||||
|
||||
*-j, --jobs #*::
|
||||
Set the maximum number of facetize worker processes. A value of 1 forces serial processing. The default value of 0 selects a conservative automatic limit based on available CPUs and memory. Memory checks may delay or reduce parallel work even when a larger value is requested. In per-region BoT mode the same limit controls parallel CSG reference sampling and initial Manifold Boolean evaluation.
|
||||
|
||||
|
||||
*-s, --suffix*::
|
||||
User specified suffix to use avoiding naming conflicts (naming conflict avoidance is needed when creating objects in *-r* mode.)
|
||||
|
||||
@@ -119,7 +133,7 @@ Resume an incomplete facetization process (will utilize cached data from a previ
|
||||
|
||||
|
||||
*--methods*::
|
||||
Accepts a comma separated list of one or more facetization methods to use. The default is to try all algorithms available as needed, but if a user knows they want to try a specific methodology they can call it out using this option.
|
||||
Accepts a comma separated list of one or more facetization methods to use. The default tries NMG tessellation first, Manifold Dual Contouring (MDC) second, and SPSR as a final fallback. Other listed methods may be selected explicitly if a user wants to try a specific methodology.
|
||||
|
||||
|
||||
*--method-opts*::
|
||||
@@ -231,21 +245,15 @@ mged>**facetize --tolerate-failures large_model large_model.partial.bot**
|
||||
|
||||
====
|
||||
|
||||
.Increase Decimation in CM Mode
|
||||
.Refine a Manifold Dual Contouring conversion
|
||||
[example]
|
||||
====
|
||||
mged>**facetize --methods CM --method-opts feature_size=0.06 d_feature_size=2.0 ellipse.r ell.bot**
|
||||
This selects MDC directly and requests a finer cell size with a larger ray
|
||||
budget than the default:
|
||||
|
||||
The default settings on this object in CM mode will produce a little over 8000 faces in the final bot, but the addition of the *d_feature_size* option with a >1.5 value has dramatically reduced the count to 104.
|
||||
mged>**facetize --methods MDC --method-opts "MDC feature_size=0.1 max_rays=400000" ellipse.r ell.bot**
|
||||
|
||||
====
|
||||
|
||||
.Decrease Decimation in CM Mode
|
||||
[example]
|
||||
====
|
||||
mged>**facetize --methods CM --method-opts feature_size=0.06 d_feature_size=0.01 ellipse.r ell.bot**
|
||||
|
||||
If the intent is preserve a more detailed mesh, reducing *decimation-feature-size* will keep more of the original triangles - in the above example, almost 250 thousand of the original 6.9 million faces were retained. NOTE: use lower values here cautiously, as extremely large meshes can be very difficult for many tools to deal with.
|
||||
Smaller feature sizes increase mesh detail, ray count, memory use, and runtime.
|
||||
|
||||
====
|
||||
|
||||
|
||||
+13
-16
@@ -679,23 +679,21 @@ Convert CSG geometry to a 3D voxel grid by:
|
||||
fill fraction
|
||||
* Level-of-detail parameter controls sub-voxel sampling
|
||||
|
||||
==== 7.5 Implicit Surface Polygonizer (Marching Cubes / Tetrahedral)
|
||||
==== 7.5 Manifold Dual Contouring
|
||||
|
||||
An implicit surface polygonizer (Bloomenthal tetrahedral marching) for
|
||||
converting any inside/outside function to a triangle mesh.
|
||||
`contour.cpp` evaluates CSG geometry directly with `librt` and constructs
|
||||
closed, oriented triangle meshes:
|
||||
|
||||
`polygonizer.c` (based on Jules Bloomenthal’s "`An Implicit Surface
|
||||
Polygonizer,`" Graphics Gems IV, 1994) converts any implicit function
|
||||
(inside/outside test) to a triangle mesh:
|
||||
|
||||
* Maintains a hash table of evaluated lattice corners and edges
|
||||
* Expanding front: starts at a seed point and spreads outward, testing
|
||||
adjacent cube faces
|
||||
* Each transitive cube is optionally decomposed into 6 tetrahedra for
|
||||
sub-cube accuracy
|
||||
* Edge-surface crossing is found by bisection (`converge`) then the
|
||||
vertex normal is estimated from finite differences
|
||||
* Used in `libanalyze` for converting CSG regions to faceted form
|
||||
* Recursively refines an implicit octree using cached axis-aligned rays along
|
||||
node box edges and interior quarter- and center-lines
|
||||
* Reuses complete ray partitions at the conforming finest grid and retains
|
||||
evaluated boundary points with analytic surface normals
|
||||
* Resolves ambiguous faces consistently and permits multiple vertices in a
|
||||
cell to preserve local topology
|
||||
* Places vertices with bounded quadratic-error minimization
|
||||
* Validates the resulting indexed mesh before returning it
|
||||
* Backs the legacy `analyze_polygonize` interface without retaining the old
|
||||
seed-driven marching-tetrahedra implementation
|
||||
|
||||
==== 7.6 Geometry Differencing (raydiff)
|
||||
|
||||
@@ -1712,7 +1710,6 @@ import
|
||||
runtime
|
||||
* *MT19937*: Mersenne Twister PRNG
|
||||
* *pbrt-v3* (derived): HLBVH construction algorithm
|
||||
* *Bloomenthal polygonizer*: implicit surface polygonization
|
||||
* *Screened Poisson Reconstruction* (Michael Kazhdan): surface
|
||||
reconstruction from point clouds
|
||||
* *Ball Pivoting Algorithm*: surface reconstruction
|
||||
|
||||
@@ -55,7 +55,6 @@ brlcad_manage_files(pbrt.txt ${DOC_DIR}/legal/embedded TRIGGER
|
||||
brlcad_manage_files(picohash.txt ${DOC_DIR}/legal/embedded TRIGGER gist)
|
||||
brlcad_manage_files(pixcii.txt ${DOC_DIR}/legal/embedded TRIGGER libicv)
|
||||
brlcad_manage_files(point_in_polygon.txt ${DOC_DIR}/legal/embedded TRIGGER libbg)
|
||||
brlcad_manage_files(polygonizer.txt ${DOC_DIR}/legal/embedded TRIGGER libanalyze)
|
||||
brlcad_manage_files(predicates.txt ${DOC_DIR}/legal/embedded TRIGGER libbg)
|
||||
brlcad_manage_files(profont.txt ${DOC_DIR}/legal/embedded TRIGGER libbu)
|
||||
brlcad_manage_files(pstdint.txt ${DOC_DIR}/legal/embedded TRIGGER libbu)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
https://www.bloomenthal.com/JBloom/code/polygonizer.c
|
||||
|
||||
Authored by Jules Bloomenthal, Xerox PARC.
|
||||
Copyright (c) Xerox Corporation, 1991. All rights reserved.
|
||||
Permission is granted to reproduce, use and distribute this code for
|
||||
any and all purposes, provided that this notice appears in all copies.
|
||||
|
||||
file:/src/libanalyze/polygonizer.c
|
||||
|
||||
@@ -61,5 +61,4 @@ Author: Paul Mackerras (paulus@cs.anu.edu.au),
|
||||
|
||||
file:/src/libtclcad/tkImgFmtPIX.c
|
||||
file:/src/tclscripts/cad_clrpick.tcl
|
||||
file:/src/tclscripts/html_library.tcl
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
BRL-CAD Itcl/Itk 4 migration
|
||||
============================
|
||||
|
||||
This records the main branch migration. The itcl3 branch retains the
|
||||
previously bundled Itcl/Itk 3 stack as a rollback option; the version
|
||||
requirements below describe the main branch.
|
||||
|
||||
Decision
|
||||
--------
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "common.h"
|
||||
|
||||
#include "analyze/defines.h"
|
||||
#include "analyze/contour.h"
|
||||
#include "analyze/debug.h"
|
||||
#include "analyze/diff.h"
|
||||
#include "analyze/density.h"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
set(
|
||||
analyze_headers
|
||||
contour.h
|
||||
debug.h
|
||||
defines.h
|
||||
density.h
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/* C O N T O U R . H
|
||||
* BRL-CAD
|
||||
*
|
||||
* Copyright (c) 2026 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.
|
||||
*/
|
||||
/** @addtogroup libanalyze
|
||||
* @{ */
|
||||
/** @file analyze/contour.h
|
||||
*
|
||||
* Ray-driven manifold dual contouring of evaluated BRL-CAD geometry.
|
||||
*/
|
||||
|
||||
#ifndef ANALYZE_CONTOUR_H
|
||||
#define ANALYZE_CONTOUR_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "vmath.h"
|
||||
#include "analyze/defines.h"
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define ANALYZE_MDC_DEFAULT_MAX_RAYS 0
|
||||
#define ANALYZE_MDC_DEFAULT_MINIMUM_FREE_MEM 150000000
|
||||
#define ANALYZE_MDC_DEFAULT_MIN_DEPTH 2
|
||||
#define ANALYZE_MDC_DEFAULT_MAX_DEPTH 10
|
||||
#define ANALYZE_MDC_MAX_DEPTH 20
|
||||
#define ANALYZE_MDC_DEFAULT_MAX_TIME 600
|
||||
|
||||
struct db_i;
|
||||
/** Resource and accuracy controls for analyze_mdc(). */
|
||||
struct analyze_mdc_params {
|
||||
/** Requested maximum finest-cell edge length. Zero selects an
|
||||
* implementation default based on the model bounds. */
|
||||
fastf_t feature_size;
|
||||
|
||||
/** Optional user ceiling for the automatically derived ray budget.
|
||||
* Zero applies only geometry, depth, time, and memory limits. */
|
||||
size_t max_rays;
|
||||
|
||||
/** Abort before available memory drops below this many bytes. */
|
||||
size_t minimum_free_mem;
|
||||
|
||||
/** Minimum and maximum power-of-two grid depths. */
|
||||
int min_depth;
|
||||
int max_depth;
|
||||
|
||||
/** Maximum wall-clock processing time in seconds. Zero is unlimited. */
|
||||
int max_time;
|
||||
|
||||
/** Emit progress diagnostics when non-zero. */
|
||||
int verbosity;
|
||||
};
|
||||
|
||||
#define ANALYZE_MDC_PARAMS_DEFAULT { \
|
||||
0.0, \
|
||||
ANALYZE_MDC_DEFAULT_MAX_RAYS, \
|
||||
ANALYZE_MDC_DEFAULT_MINIMUM_FREE_MEM, \
|
||||
ANALYZE_MDC_DEFAULT_MIN_DEPTH, \
|
||||
ANALYZE_MDC_DEFAULT_MAX_DEPTH, \
|
||||
ANALYZE_MDC_DEFAULT_MAX_TIME, \
|
||||
0 \
|
||||
}
|
||||
|
||||
enum analyze_mdc_status {
|
||||
ANALYZE_MDC_OK = 0,
|
||||
ANALYZE_MDC_INVALID_INPUT = 1,
|
||||
ANALYZE_MDC_PREP_FAILED = 2,
|
||||
ANALYZE_MDC_NO_SURFACE = 3,
|
||||
ANALYZE_MDC_RAY_LIMIT = 4,
|
||||
ANALYZE_MDC_TIMEOUT = 5,
|
||||
ANALYZE_MDC_MEMORY_LIMIT = 6,
|
||||
ANALYZE_MDC_AMBIGUOUS = 7,
|
||||
ANALYZE_MDC_NOT_MANIFOLD = 8
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate @p object with librt and construct an indexed triangle mesh.
|
||||
*
|
||||
* On success, the caller owns @p faces and @p vertices and must release them
|
||||
* with bu_free(). Failure leaves all outputs empty.
|
||||
*/
|
||||
ANALYZE_EXPORT extern enum analyze_mdc_status
|
||||
analyze_mdc(int **faces, size_t *num_faces, point_t **vertices,
|
||||
size_t *num_vertices, const char *object, struct db_i *dbip,
|
||||
const struct analyze_mdc_params *params);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* ANALYZE_CONTOUR_H */
|
||||
|
||||
/** @} */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "stroustrup"
|
||||
* End:
|
||||
* ex: shiftwidth=4 tabstop=8
|
||||
*/
|
||||
@@ -43,9 +43,29 @@ struct analyze_polygonize_params {
|
||||
size_t minimum_free_mem;
|
||||
int verbosity;
|
||||
};
|
||||
#define ANALYZE_POLYGONIZE_PARAMS_DEFAULT { 0, 0, 30, 150000000, 0 }
|
||||
#define ANALYZE_POLYGONIZE_DEFAULT_MAX_CYCLE_TIME 30
|
||||
#define ANALYZE_POLYGONIZE_DEFAULT_MINIMUM_FREE_MEM 150000000
|
||||
#define ANALYZE_POLYGONIZE_PARAMS_DEFAULT { 0, 0, \
|
||||
ANALYZE_POLYGONIZE_DEFAULT_MAX_CYCLE_TIME, \
|
||||
ANALYZE_POLYGONIZE_DEFAULT_MINIMUM_FREE_MEM, 0 }
|
||||
|
||||
/**
|
||||
* Legacy polygonization interface, implemented by analyze_mdc().
|
||||
*
|
||||
* @p size is the requested maximum cell edge length. @p p_s is retained for
|
||||
* source and binary compatibility but is no longer used as a starting seed.
|
||||
* The caller owns successful output arrays and must release them with
|
||||
* bu_free(). Failure leaves all outputs empty.
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on invalid input or polygonization failure
|
||||
* @return 2 when a time limit is reached
|
||||
* @return 3 when the minimum-free-memory limit is reached
|
||||
*/
|
||||
ANALYZE_EXPORT extern int
|
||||
analyze_polygonize(int **faces, int *num_faces, point_t **vertices, int *num_vertices, fastf_t size, point_t p_s, const char *obj, struct db_i *dbip, struct analyze_polygonize_params *p);
|
||||
analyze_polygonize(int **faces, int *num_faces, point_t **vertices,
|
||||
int *num_vertices, fastf_t size, point_t p_s, const char *obj,
|
||||
struct db_i *dbip, struct analyze_polygonize_params *p);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "bg/clip.h"
|
||||
#include "bg/lseg.h"
|
||||
#include "bg/obr.h"
|
||||
#include "bg/pca.h"
|
||||
#include "bg/plane.h"
|
||||
#include "bg/polygon.h"
|
||||
#include "bg/sat.h"
|
||||
|
||||
+4
-4
@@ -50,12 +50,12 @@ BG_EXPORT extern int bg_lseg_clip(fastf_t *xp1, fastf_t *yp1, fastf_t *xp2, fast
|
||||
* The RPP has faces parallel to the coordinate planes and is defined
|
||||
* by a minimum point and a maximum point.
|
||||
*
|
||||
* FIXME: the function name implies this takes a point,dir for a,b but
|
||||
* it actually takes a line segment going from points a to b!
|
||||
* Despite its historical name, this function clips the finite line segment
|
||||
* from a to b.
|
||||
*
|
||||
* Returns -
|
||||
* 0 if ray does not hit RPP,
|
||||
* !0 if ray hits RPP.
|
||||
* 0 if the segment does not hit the RPP,
|
||||
* !0 if the segment hits the RPP.
|
||||
*
|
||||
* Implicit Return -
|
||||
* if !0 was returned, "a" and "b" have been clipped to the RPP.
|
||||
|
||||
+6
-3
@@ -126,9 +126,12 @@ BG_EXPORT extern int bg_3d_coplanar_obr(point_t *center,
|
||||
* \endverbatim
|
||||
*
|
||||
*
|
||||
* @param[out] pnts eight points of oriented bounding box
|
||||
* @param points_3d array of 3D points
|
||||
* @param pnt_cnt number of points in pnts array
|
||||
* @param[out] pnts eight non-NULL, caller-provided point_t storage
|
||||
* locations for the oriented bounding box vertices
|
||||
* @param[in] points_3d flat array containing 3 * pnt_cnt coordinate values
|
||||
* @param[in] pnt_cnt number of points in points_3d
|
||||
*
|
||||
* @return 0 on success and -1 for invalid input or when no box can be fit
|
||||
*/
|
||||
BG_EXPORT extern int bg_3d_obb(point_t **pnts,
|
||||
const fastf_t *points_3d,
|
||||
|
||||
+4
-4
@@ -21,7 +21,7 @@
|
||||
/*----------------------------------------------------------------------*/
|
||||
/** @addtogroup bg_pca
|
||||
*
|
||||
* Principle Component Analysis
|
||||
* Principal Component Analysis
|
||||
*
|
||||
* Calculates an XYZ coordinate system such that it aligns with the largest
|
||||
* variations in the supplied data. Intuitively, it "aligns" with the
|
||||
@@ -50,7 +50,7 @@
|
||||
* point_t p;
|
||||
* for (size_t i = 0; i < pntcnt; i++) {
|
||||
* MAT4X3PNT(p, RT, pnts[i]);
|
||||
* VMOVE(pnts[i], v);
|
||||
* VMOVE(pnts[i], p);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
@@ -69,7 +69,7 @@ __BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Perform a Principle Component Analysis on a set of points.
|
||||
* Perform a Principal Component Analysis on a set of points.
|
||||
*
|
||||
* Outputs are a center point and XYZ vectors for the coordinate system.
|
||||
*
|
||||
@@ -88,7 +88,7 @@ BG_EXPORT extern int bg_pca(point_t *c, vect_t *xaxis, vect_t *yaxis, vect_t *za
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* BG_PLANE_H */
|
||||
#endif /* BG_PCA_H */
|
||||
/** @} */
|
||||
/*
|
||||
* Local Variables:
|
||||
|
||||
+7
-4
@@ -1171,9 +1171,10 @@ BG_EXPORT extern int bg_isect_planes(point_t pt,
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Given an origin and a normal, create a plane_t.
|
||||
* Given an origin and a normal, create a plane_t with a unit normal.
|
||||
* The input point and normal are not modified. A zero-length normal fails.
|
||||
*/
|
||||
BG_EXPORT extern int bg_plane_pt_nrml(plane_t *p, point_t pt, vect_t nrml);
|
||||
BG_EXPORT extern int bg_plane_pt_nrml(plane_t *p, const point_t pt, const vect_t nrml);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
@@ -1188,13 +1189,15 @@ BG_EXPORT extern int bg_fit_plane(point_t *c, vect_t *n, size_t npnts, point_t *
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Find the closest U,V point on the plane p to 3d point pt.
|
||||
* Find the closest U,V point on the plane p to 3d point pt. The plane normal
|
||||
* need not be unit length.
|
||||
*/
|
||||
BG_EXPORT extern int bg_plane_closest_pt(fastf_t *u, fastf_t *v, plane_t *p, point_t *pt);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Return the 3D point on the plane at parametric coordinates u, v.
|
||||
* Return the 3D point on the plane at parametric coordinates u, v. The plane
|
||||
* normal need not be unit length.
|
||||
*/
|
||||
BG_EXPORT extern int bg_plane_pt_at(point_t *pt, plane_t *p, fastf_t u, fastf_t v);
|
||||
|
||||
|
||||
@@ -293,6 +293,7 @@ BG_EXPORT extern int bg_3d_polygon_area(fastf_t *area, size_t npts, const point_
|
||||
* @param[in] npts Number of point_ts, stored in pts
|
||||
* @param[in] pts all points of the polygon, sorted counter-clockwise.
|
||||
* The array mustn't contain duplicated points or non-coplanar points.
|
||||
* A zero-area polygon fails.
|
||||
*
|
||||
* @return 0 if calculation was successful
|
||||
* @return 1 if calculation failed, e.g. because one in-parameter is a NULL-pointer
|
||||
@@ -307,7 +308,7 @@ BG_EXPORT extern int bg_3d_polygon_centroid(point_t *cent, size_t npts, const po
|
||||
*@param[in] npts Number of points, pts contains
|
||||
*@param pts Array of point_ts, building a convex polygon. Duplicated points
|
||||
*aren't allowed. The points in the array will be sorted counter-clockwise.
|
||||
*@param[in] cmp Plane equation of the polygon
|
||||
*@param[in] cmp Plane equation of the polygon. Its normal must be nonzero.
|
||||
*
|
||||
*@return 0 if calculation was successful
|
||||
*@return 1 if calculation failed, e.g. because pts is a NULL-pointer
|
||||
|
||||
+20
-8
@@ -39,7 +39,9 @@
|
||||
__BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* Test for an intersection between a line and an Axis-Aligned Bounding Box (AABB).
|
||||
* Test for an intersection between an infinite line and an Axis-Aligned
|
||||
* Bounding Box (AABB). ldir need not be unit length, but must be nonzero.
|
||||
* aabb_extent supplies the positive half extents along the coordinate axes.
|
||||
*
|
||||
* Returns 1 if they intersect, 0 otherwise.
|
||||
*/
|
||||
@@ -50,7 +52,10 @@ bg_sat_line_aabb(
|
||||
);
|
||||
|
||||
/**
|
||||
* Test for an intersection between a line and an Oriented Bounding Box (OBB).
|
||||
* Test for an intersection between an infinite line and an Oriented Bounding
|
||||
* Box (OBB). ldir need not be unit length, but must be nonzero. Each OBB
|
||||
* extent vector points from the center to a face center; nonzero vectors must
|
||||
* be mutually perpendicular, and a zero vector represents a degenerate axis.
|
||||
*
|
||||
* Returns 1 if they intersect, 0 otherwise.
|
||||
*/
|
||||
@@ -61,7 +66,9 @@ bg_sat_line_obb(
|
||||
);
|
||||
|
||||
/**
|
||||
* Test for an intersection between a triangle and an Axis-Aligned Bounding Box (AABB).
|
||||
* Test for an intersection between a triangle and an Axis-Aligned Bounding
|
||||
* Box (AABB). extent supplies the positive half extents along the coordinate
|
||||
* axes.
|
||||
*
|
||||
* Returns 1 if they intersect, 0 otherwise.
|
||||
*/
|
||||
@@ -72,7 +79,10 @@ bg_sat_tri_aabb(
|
||||
);
|
||||
|
||||
/**
|
||||
* Test for an intersection between a triangle and an Oriented Bounding Box (OBB).
|
||||
* Test for an intersection between a triangle and an Oriented Bounding Box
|
||||
* (OBB). Each extent vector points from the center to a face center; nonzero
|
||||
* vectors must be mutually perpendicular, and a zero vector represents a
|
||||
* degenerate axis.
|
||||
*
|
||||
* Returns 1 if they intersect, 0 otherwise.
|
||||
*/
|
||||
@@ -85,8 +95,9 @@ bg_sat_tri_obb(
|
||||
/**
|
||||
* Test for an intersection between an Axis-Aligned Bounding Box (AABB) and an
|
||||
* Oriented Bounding Box (OBB). The latter is defined by a center point and
|
||||
* three perpendicular vectors from the center to the centers of the various
|
||||
* faces.
|
||||
* three extent vectors from the center to the centers of the various faces.
|
||||
* Nonzero extent vectors must be mutually perpendicular; a zero vector
|
||||
* represents a degenerate axis.
|
||||
*
|
||||
* Returns 1 if they intersect, 0 otherwise.
|
||||
*/
|
||||
@@ -98,8 +109,9 @@ bg_sat_aabb_obb(
|
||||
|
||||
/**
|
||||
* Test for an intersection between two Oriented Bounding Boxes (OBBs). The
|
||||
* boxes are defined by a center point and three perpendicular vectors from the
|
||||
* center to the centers of the various faces.
|
||||
* boxes are defined by a center point and three extent vectors from the center
|
||||
* to the centers of the various faces. Nonzero extent vectors must be
|
||||
* mutually perpendicular; a zero vector represents a degenerate axis.
|
||||
*
|
||||
* Returns 1 if they intersect, 0 otherwise.
|
||||
*/
|
||||
|
||||
+127
-5
@@ -67,6 +67,7 @@
|
||||
#define BG_SPSR_H
|
||||
|
||||
#include "common.h"
|
||||
#include <stdint.h>
|
||||
#include "vmath.h"
|
||||
#include "bg/defines.h"
|
||||
|
||||
@@ -109,7 +110,7 @@ struct bg_3d_spsr_opts {
|
||||
#define BG_3D_SPSR_BOUNDARY_DIRICHLET 3
|
||||
|
||||
#define BG_3D_SPSR_DEFAULT_DEGREE 1 /* DEFAULT_FEM_DEGREE */
|
||||
#define BG_3D_SPSR_DEFAULT_DEPTH 11
|
||||
#define BG_3D_SPSR_DEFAULT_DEPTH 8
|
||||
#define BG_3D_SPSR_DEFAULT_KERNELDEPTH 0
|
||||
#define BG_3D_SPSR_DEFAULT_ITERATIONS 0
|
||||
#define BG_3D_SPSR_DEFAULT_FULL_DEPTH 0
|
||||
@@ -117,13 +118,13 @@ struct bg_3d_spsr_opts {
|
||||
#define BG_3D_SPSR_DEFAULT_BASEVCYCLES 0
|
||||
#define BG_3D_SPSR_DEFAULT_MAX_MEM 0
|
||||
#define BG_3D_SPSR_DEFAULT_THREADS 0
|
||||
#define BG_3D_SPSR_DEFAULT_SAMPLES_PER_NODE 1.1
|
||||
#define BG_3D_SPSR_DEFAULT_SCALE 1.0
|
||||
#define BG_3D_SPSR_DEFAULT_SAMPLES_PER_NODE 1.5
|
||||
#define BG_3D_SPSR_DEFAULT_SCALE 1.1
|
||||
#define BG_3D_SPSR_DEFAULT_WIDTH 0.0
|
||||
#define BG_3D_SPSR_DEFAULT_CONFIDENCE 0.0
|
||||
#define BG_3D_SPSR_DEFAULT_CONFIDENCE_BIAS 0.0
|
||||
#define BG_3D_SPSR_DEFAULT_CGSOLVER_ACCURACY 1.0e-3
|
||||
#define BG_3D_SPSR_DEFAULT_POINT_WEIGHT 8.0 /* DefaultPointWeightMultiplier * Degree */
|
||||
#define BG_3D_SPSR_DEFAULT_POINT_WEIGHT 2.0
|
||||
#define BG_3D_SPSR_DEFAULT_NONMANIFOLD 0
|
||||
#define BG_3D_SPSR_DEFAULT_LINEARFIT 0
|
||||
#define BG_3D_SPSR_DEFAULT_EXACT 1
|
||||
@@ -167,10 +168,131 @@ struct bg_3d_spsr_opts {
|
||||
* @return 0 if successful, else error
|
||||
*
|
||||
*/
|
||||
BG_EXPORT int bg_3d_spsr(int **faces, int *num_faces, point_t **vertices, int *num_vertices,
|
||||
DEPRECATED BG_EXPORT int bg_3d_spsr(int **faces, int *num_faces, point_t **vertices, int *num_vertices,
|
||||
const point_t *input_points_3d, const vect_t *input_normals_3d,
|
||||
int num_input_pnts, struct bg_3d_spsr_opts *opts);
|
||||
|
||||
/** Reasons the SPSR solver may request additional source samples. */
|
||||
#define BG_3D_SPSR_REFINE_RESIDUAL 0x01u
|
||||
#define BG_3D_SPSR_REFINE_NORMAL 0x02u
|
||||
#define BG_3D_SPSR_REFINE_DENSITY 0x04u
|
||||
#define BG_3D_SPSR_REFINE_SURFACE_VARIATION 0x08u
|
||||
|
||||
/** Adaptive SPSR termination states. */
|
||||
#define BG_3D_SPSR_COMPLETE 0
|
||||
#define BG_3D_SPSR_CALLBACK_STOP 1
|
||||
#define BG_3D_SPSR_POINT_LIMIT 2
|
||||
#define BG_3D_SPSR_TIME_LIMIT 3
|
||||
#define BG_3D_SPSR_NO_NEW_SAMPLES 4
|
||||
#define BG_3D_SPSR_SOLVER_ERROR 5
|
||||
|
||||
/**
|
||||
* One oriented source sample. A positive @p thickness records the length of
|
||||
* the solid ray partition that supplied the sample. Non-zero equal pair IDs
|
||||
* identify the entry and exit samples of the same partition.
|
||||
*/
|
||||
struct bg_3d_spsr_sample {
|
||||
point_t point;
|
||||
vect_t normal;
|
||||
fastf_t thickness;
|
||||
uint64_t pair_id;
|
||||
};
|
||||
|
||||
/** A spatial location at which the solver would benefit from more samples. */
|
||||
struct bg_3d_spsr_refinement_hint {
|
||||
point_t point;
|
||||
vect_t normal;
|
||||
fastf_t error;
|
||||
unsigned int reasons;
|
||||
};
|
||||
|
||||
/** Source-to-candidate measurements supplied by an adaptive callback. */
|
||||
struct bg_3d_spsr_validation {
|
||||
size_t ray_count;
|
||||
size_t source_hit_rays;
|
||||
size_t partition_mismatch_rays;
|
||||
size_t thin_partition_count;
|
||||
size_t thin_partition_mismatches;
|
||||
fastf_t endpoint_error_p95;
|
||||
fastf_t endpoint_error_p99;
|
||||
fastf_t chord_error_fraction;
|
||||
fastf_t surface_area_error_fraction;
|
||||
fastf_t volume_error_fraction;
|
||||
int passed;
|
||||
};
|
||||
|
||||
/** Information passed to an adaptive source-sampling callback. */
|
||||
struct bg_3d_spsr_refinement_request {
|
||||
size_t pass;
|
||||
fastf_t target_feature_size;
|
||||
double remaining_time;
|
||||
const point_t *vertices;
|
||||
size_t vertex_count;
|
||||
const int *faces;
|
||||
size_t face_count;
|
||||
const struct bg_3d_spsr_refinement_hint *hints;
|
||||
size_t hint_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback response. Sample storage remains owned by the callback and need
|
||||
* only remain valid until the callback returns; libbg copies it immediately.
|
||||
*/
|
||||
struct bg_3d_spsr_refinement_response {
|
||||
const struct bg_3d_spsr_sample *samples;
|
||||
size_t sample_count;
|
||||
struct bg_3d_spsr_validation validation;
|
||||
/** Non-zero asks the adaptive driver to stop after this candidate. */
|
||||
int stop_refinement;
|
||||
};
|
||||
|
||||
typedef int (*bg_3d_spsr_refinement_func_t)(
|
||||
struct bg_3d_spsr_refinement_response *response,
|
||||
const struct bg_3d_spsr_refinement_request *request,
|
||||
void *client_data);
|
||||
|
||||
/** Options controlling a bounded adaptive SPSR reconstruction. */
|
||||
struct bg_3d_spsr_adaptive_opts {
|
||||
struct bg_3d_spsr_opts solver;
|
||||
size_t max_refinement_passes;
|
||||
size_t max_points;
|
||||
fastf_t target_feature_size;
|
||||
double max_time;
|
||||
};
|
||||
|
||||
/** Last-resort solve budget; callbacks may stop earlier when progress stalls. */
|
||||
#define BG_3D_SPSR_DEFAULT_REFINEMENT_PASSES 8
|
||||
#define BG_3D_SPSR_ADAPTIVE_OPTS_DEFAULT { \
|
||||
BG_3D_SPSR_OPTS_DEFAULT, \
|
||||
BG_3D_SPSR_DEFAULT_REFINEMENT_PASSES, \
|
||||
0, \
|
||||
0.0, \
|
||||
0.0 }
|
||||
|
||||
/** Summary of an adaptive SPSR attempt. */
|
||||
struct bg_3d_spsr_report {
|
||||
size_t solve_count;
|
||||
size_t initial_sample_count;
|
||||
size_t final_sample_count;
|
||||
size_t requested_sample_count;
|
||||
size_t accepted_sample_count;
|
||||
double elapsed_time;
|
||||
int termination;
|
||||
struct bg_3d_spsr_validation validation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reconstruct a surface and, when requested, obtain targeted additional
|
||||
* samples from @p refine. A callback is required when refinement passes are
|
||||
* enabled. The final candidate must be marked as passed by the callback.
|
||||
*/
|
||||
BG_EXPORT int bg_3d_spsr_adaptive(int **faces, int *num_faces,
|
||||
point_t **vertices, int *num_vertices,
|
||||
const struct bg_3d_spsr_sample *input_samples, size_t sample_count,
|
||||
const struct bg_3d_spsr_adaptive_opts *opts,
|
||||
bg_3d_spsr_refinement_func_t refine, void *client_data,
|
||||
struct bg_3d_spsr_report *report);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* BG_SPSR_H */
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ BG_EXPORT extern double bg_tri_closest_pt(
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* BG_TRI_TRI_H */
|
||||
#endif /* BG_TRI_PT_H */
|
||||
/** @} */
|
||||
/*
|
||||
* Local Variables:
|
||||
|
||||
@@ -54,7 +54,7 @@ BG_EXPORT extern int bg_isect_tri_line(point_t *isect,
|
||||
* If isect is non-NULL, it is written only when an intersection is found.
|
||||
*/
|
||||
BG_EXPORT extern int bg_isect_tri_ray(const point_t orig,
|
||||
const point_t dir,
|
||||
const vect_t dir,
|
||||
const point_t vert0,
|
||||
const point_t vert1,
|
||||
const point_t vert2,
|
||||
|
||||
+22
-1
@@ -87,7 +87,11 @@ BG_EXPORT extern int bg_trimesh_oriented(int vcnt, int fcnt, fastf_t *v, int *f)
|
||||
/**
|
||||
* Check if a mesh is topologically solid. Returns 1 if the mesh is NOT SOLID
|
||||
* and 0 if the mesh is SOLID. A SOLID (0) outcome indicates the mesh satisfies
|
||||
* all three criteria: Closed, Manifold, Oriented
|
||||
* all three criteria: Closed, Manifold, Oriented. If @p bedges is non-NULL,
|
||||
* it is set to NULL when no edge diagnostics are present, or to a bu_calloc()
|
||||
* allocated array of vertex-index pairs for unmatched, misoriented, and excess
|
||||
* edges. The caller must bu_free() a non-NULL result. Use
|
||||
* bg_trimesh_solid2() when structured diagnostics and their counts are needed.
|
||||
*/
|
||||
BG_EXPORT extern int bg_trimesh_solid(int vcnt, int fcnt, fastf_t *v, int *f, int **bedges);
|
||||
|
||||
@@ -120,6 +124,23 @@ BG_EXPORT extern int bg_trimesh_unmatched_edges(int num_edges, struct bg_trimesh
|
||||
BG_EXPORT extern int bg_trimesh_misoriented_edges(int num_edges, struct bg_trimesh_halfedge *edge_list, bg_edge_error_funct_t error_edge_func, void *data);
|
||||
BG_EXPORT extern int bg_trimesh_excess_edges(int num_edges, struct bg_trimesh_halfedge *edge_list, bg_edge_error_funct_t error_edge_func, void *data);
|
||||
BG_EXPORT extern int bg_trimesh_solid2(int vcnt, int fcnt, fastf_t *v, int *f, struct bg_trimesh_solid_errors *errors);
|
||||
|
||||
/**
|
||||
* Report geometric intersections between faces of one triangle mesh.
|
||||
* Contact confined to a shared indexed vertex or edge is allowed; overlap
|
||||
* beyond that shared feature and contact between unconnected faces count as
|
||||
* self intersections. This test does not check manifoldness or closure.
|
||||
*
|
||||
* @param[in] faces flat array of three vertex indices per triangle
|
||||
* @param[in] num_faces number of triangles
|
||||
* @param[in] points array of vertex positions
|
||||
* @param[in] num_points number of vertices
|
||||
*
|
||||
* @return 1 if self intersecting, 0 if not, -1 for malformed input
|
||||
* (invalid indices, non-finite vertices, or degenerate faces) or a failed check.
|
||||
*/
|
||||
BG_EXPORT extern int bg_trimesh_self_isect(const int *faces, size_t num_faces,
|
||||
const point_t *points, size_t num_points);
|
||||
BG_EXPORT extern int bg_trimesh_hanging_nodes(int num_vertices, int num_faces, fastf_t *vertices, int *faces, struct bg_trimesh_solid_errors *errors);
|
||||
|
||||
BG_EXPORT extern struct bg_trimesh_halfedge * bg_trimesh_generate_edge_list(int fcnt, int *f);
|
||||
|
||||
+15
-12
@@ -214,8 +214,8 @@ BN_EXPORT extern void bn_mat_ae(mat_t m,
|
||||
double elev);
|
||||
|
||||
/**
|
||||
* Find the azimuth and elevation angles that correspond to the
|
||||
* direction (not including twist) given by a direction vector.
|
||||
* Find the azimuth and elevation angles, in degrees, that correspond
|
||||
* to the direction (not including twist) given by a direction vector.
|
||||
*/
|
||||
BN_EXPORT extern void bn_ae_vec(fastf_t *azp,
|
||||
fastf_t *elp,
|
||||
@@ -236,14 +236,16 @@ BN_EXPORT extern void bn_aet_vec(fastf_t *az,
|
||||
fastf_t accuracy);
|
||||
|
||||
/**
|
||||
* Find a unit vector from the origin given azimuth and elevation.
|
||||
* Find a unit vector from the origin given azimuth and elevation in
|
||||
* radians.
|
||||
*/
|
||||
BN_EXPORT extern void bn_vec_ae(vect_t vec,
|
||||
fastf_t az,
|
||||
fastf_t el);
|
||||
|
||||
/**
|
||||
* Find a vector from the origin given azimuth, elevation, and distance.
|
||||
* Find a vector from the origin given azimuth and elevation in radians,
|
||||
* and distance.
|
||||
*/
|
||||
BN_EXPORT extern void bn_vec_aed(vect_t vec,
|
||||
fastf_t az,
|
||||
@@ -310,8 +312,10 @@ BN_EXPORT extern void bn_vec_perp(vect_t new_vec,
|
||||
* space by the angle between the two. There are many candidate
|
||||
* matrices.
|
||||
*
|
||||
* The input 'from' and 'to' vectors need not be unit length.
|
||||
* MAT4X3VEC(to, m, from) is the identity that is created.
|
||||
* The input 'from' and 'to' vectors need not be unit length. They are
|
||||
* normalized internally. Near-parallel inputs are handled using the
|
||||
* angular tolerance in 'tol'. If either input cannot be normalized,
|
||||
* the result is the identity matrix.
|
||||
*
|
||||
*/
|
||||
BN_EXPORT extern void bn_mat_fromto(mat_t m,
|
||||
@@ -344,12 +348,11 @@ BN_EXPORT extern void bn_mat_zrot(mat_t m,
|
||||
double cosz);
|
||||
|
||||
/**
|
||||
* Given a direction vector D of unit length, product a matrix which
|
||||
* rotates that vector D onto the -Z axis. This matrix will be
|
||||
* suitable for use as a "model2view" matrix.
|
||||
*
|
||||
* XXX This routine will fail if the vector is already more or less
|
||||
* aligned with the Z axis.
|
||||
* Given a nonzero direction vector D, produce a matrix which
|
||||
* rotates D onto the -Z axis. D is normalized internally. Z-axis
|
||||
* directions use a deterministic roll, and a zero direction produces
|
||||
* the identity matrix. This matrix will be suitable for use as a
|
||||
* model2view matrix.
|
||||
*
|
||||
* This is done in several steps.
|
||||
*
|
||||
|
||||
@@ -37,11 +37,42 @@ __BEGIN_DECLS
|
||||
|
||||
typedef struct bn_multipoly {
|
||||
uint32_t magic;
|
||||
/**< Number of coefficients in the first polynomial variable. */
|
||||
int dgrs;
|
||||
/**< Number of coefficients in the second polynomial variable. */
|
||||
int dgrt;
|
||||
/**< Coefficient of S^s * T^t is cf[s][t]. */
|
||||
double **cf;
|
||||
} bn_multipoly_t;
|
||||
|
||||
/**
|
||||
* Allocate a zero-valued bivariate polynomial with the specified
|
||||
* coefficient counts. Both counts must be positive.
|
||||
*/
|
||||
BN_EXPORT extern struct bn_multipoly *bn_multipoly_new(int dgrs, int dgrt);
|
||||
|
||||
/** Release a bivariate polynomial allocated by bn_multipoly_new(). */
|
||||
BN_EXPORT extern void bn_multipoly_free(struct bn_multipoly *poly);
|
||||
|
||||
/** Grow a polynomial to at least the specified coefficient counts. */
|
||||
BN_EXPORT extern struct bn_multipoly *bn_multipoly_grow(struct bn_multipoly *poly,
|
||||
int dgrs,
|
||||
int dgrt);
|
||||
|
||||
/** Set the coefficient of S^s * T^t, growing the polynomial as needed. */
|
||||
BN_EXPORT extern struct bn_multipoly *bn_multipoly_set(struct bn_multipoly *poly,
|
||||
int s,
|
||||
int t,
|
||||
double value);
|
||||
|
||||
/** Return the sum of two bivariate polynomials. */
|
||||
BN_EXPORT extern struct bn_multipoly *bn_multipoly_add(const struct bn_multipoly *p1,
|
||||
const struct bn_multipoly *p2);
|
||||
|
||||
/** Return the product of two bivariate polynomials. */
|
||||
BN_EXPORT extern struct bn_multipoly *bn_multipoly_mul(const struct bn_multipoly *p1,
|
||||
const struct bn_multipoly *p2);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* BN_MULTIPOLY_H */
|
||||
|
||||
+20
-4
@@ -45,7 +45,10 @@ __BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* Polynomial data type
|
||||
* bn_poly->cf[n] corresponds to X^n
|
||||
*
|
||||
* Coefficients are stored from the highest to the lowest degree:
|
||||
* `cf[0]` is the coefficient of `X^dgr` and `cf[dgr]` is the
|
||||
* constant coefficient.
|
||||
*/
|
||||
typedef struct bn_poly {
|
||||
uint32_t magic;
|
||||
@@ -63,6 +66,9 @@ typedef struct bn_poly {
|
||||
*
|
||||
* @brief
|
||||
* multiply two polynomials
|
||||
*
|
||||
* The output may alias either input. If the result exceeds
|
||||
* BN_MAX_POLY_DEGREE, returns BN_POLY_NULL without modifying product.
|
||||
*/
|
||||
BN_EXPORT extern struct bn_poly *bn_poly_mul(struct bn_poly *product,
|
||||
const struct bn_poly *m1,
|
||||
@@ -81,6 +87,8 @@ BN_EXPORT extern struct bn_poly *bn_poly_scale(struct bn_poly *eqn,
|
||||
* bn_poly_add
|
||||
* @brief
|
||||
* add two polynomials
|
||||
*
|
||||
* The output may alias either input.
|
||||
*/
|
||||
BN_EXPORT extern struct bn_poly *bn_poly_add(struct bn_poly *sum,
|
||||
const struct bn_poly *poly1,
|
||||
@@ -90,6 +98,8 @@ BN_EXPORT extern struct bn_poly *bn_poly_add(struct bn_poly *sum,
|
||||
* bn_poly_sub
|
||||
* @brief
|
||||
* subtract two polynomials
|
||||
*
|
||||
* The output may alias either input.
|
||||
*/
|
||||
BN_EXPORT extern struct bn_poly *bn_poly_sub(struct bn_poly *diff,
|
||||
const struct bn_poly *poly1,
|
||||
@@ -98,7 +108,10 @@ BN_EXPORT extern struct bn_poly *bn_poly_sub(struct bn_poly *diff,
|
||||
/**
|
||||
* @brief
|
||||
* Divides any polynomial into any other polynomial using synthetic
|
||||
* division. Both polynomials must have real coefficients.
|
||||
* division. Both polynomials must have real coefficients and the
|
||||
* divisor's leading coefficient must be nonzero. The quotient and
|
||||
* remainder outputs must be distinct; the quotient may alias the
|
||||
* dividend. All other output/input pairs must be distinct.
|
||||
*/
|
||||
BN_EXPORT extern void bn_poly_synthetic_division(struct bn_poly *quo,
|
||||
struct bn_poly *rem,
|
||||
@@ -108,7 +121,8 @@ BN_EXPORT extern void bn_poly_synthetic_division(struct bn_poly *quo,
|
||||
/**
|
||||
*@brief
|
||||
* Uses the quadratic formula to find the roots (in `complex' form) of
|
||||
* any quadratic equation with real coefficients.
|
||||
* any quadratic equation with real coefficients. A nonzero leading
|
||||
* coefficient need not be one.
|
||||
*
|
||||
* @return 1 for success
|
||||
* @return 0 for fail.
|
||||
@@ -144,6 +158,7 @@ BN_EXPORT extern int bn_poly_quadratic_roots(struct bn_complex roots[],
|
||||
* If D < 0, there will be three unequal real roots.
|
||||
*
|
||||
* Returns 1 for success, 0 for fail.
|
||||
* A nonzero leading coefficient need not be one.
|
||||
*/
|
||||
BN_EXPORT extern int bn_poly_cubic_roots(struct bn_complex roots[],
|
||||
const struct bn_poly *eqn);
|
||||
@@ -151,7 +166,8 @@ BN_EXPORT extern int bn_poly_cubic_roots(struct bn_complex roots[],
|
||||
/**
|
||||
*@brief
|
||||
* Uses the quartic formula to find the roots (in `complex' form)
|
||||
* of any quartic equation with real coefficients.
|
||||
* of any quartic equation with real coefficients. A nonzero leading
|
||||
* coefficient need not be one.
|
||||
*
|
||||
* @return 1 for success
|
||||
* @return 0 for fail.
|
||||
|
||||
+4
-3
@@ -100,8 +100,8 @@ BN_EXPORT extern void quat_double(quat_t qout,
|
||||
/**
|
||||
*@brief Gives the bisector of quaternions q1 and q2.
|
||||
*
|
||||
* (Could be done with quat_slerp and factor 0.5)
|
||||
* [I believe they must be unit quaternions this to work]
|
||||
* Inputs must be unit quaternions. Antipodal inputs use a valid
|
||||
* great-circle midpoint.
|
||||
*/
|
||||
BN_EXPORT extern void quat_bisect(quat_t qout,
|
||||
const quat_t q1,
|
||||
@@ -161,7 +161,8 @@ BN_EXPORT extern void quat_exp(quat_t out,
|
||||
|
||||
/**
|
||||
*@brief
|
||||
* Take the natural logarithm of a unit quaternion.
|
||||
* Take the natural logarithm of a unit quaternion. The identity
|
||||
* quaternion maps to the zero quaternion.
|
||||
* Code by Ken Shoemake.
|
||||
*/
|
||||
BN_EXPORT extern void quat_log(quat_t out,
|
||||
|
||||
+16
-9
@@ -205,23 +205,30 @@ BU_EXPORT extern int bu_sscanf(const char *src, const char *fmt, ...) _BU_ATTR_S
|
||||
/** Routines for scanning certain kinds of data. */
|
||||
|
||||
/**
|
||||
* Scans a sequence of fastf_t numbers from a string or stdin
|
||||
* Scans a sequence of fastf_t numbers from a string or stdin.
|
||||
*
|
||||
* Scanning fastf_t numbers with bu_sscanf() is difficult, because
|
||||
* doing so requires scanning to some intermediate type like double
|
||||
* and then assigning to the fastf_t variable to convert the value to
|
||||
* whatever type fastf_t really is. This function makes it possible
|
||||
* to scan a series of fastf_t numbers separated by some character(s)
|
||||
* easily, by doing the required conversion internally to the
|
||||
* functions. As series of delimiter characters will be skipped,
|
||||
* empty scan fields are not supported (e.g., "0.0,,0.0,1.0" will scan
|
||||
* as 3 fields, not 4 with the 2nd skipped).
|
||||
* to scan a series of fastf_t numbers easily, by doing the required
|
||||
* conversion internally. Delimiters form a non-empty character set:
|
||||
* one or more delimiter characters must separate values, and repeated
|
||||
* delimiters are skipped. Empty scan fields are therefore not
|
||||
* supported (e.g., "0.0,,0.0,1.0" scans as 3 fields, not 4 with the
|
||||
* second skipped). A trailing delimiter is not consumed after the
|
||||
* final requested value.
|
||||
*
|
||||
* @param[out] c Returns number of characters scanned by the function
|
||||
* @param[out] c Optional destination for the number of input characters
|
||||
* consumed. It is set to zero before scanning and remains zero for
|
||||
* invalid arguments or when no value is scanned.
|
||||
* @param[in] src A source string to scan from, or NULL to read from stdin
|
||||
* @param[in] delim Any delimiter character(s) to skip between scan values
|
||||
* @param[in] delim Non-empty set of delimiter characters to skip between
|
||||
* scan values
|
||||
* @param[in] n Number of fastf_t values to scan from the src input string
|
||||
* @param[out] ... Pointers to fastf_t for storing scanned values (optional)
|
||||
* @param[out] ... Exactly n fastf_t pointers for storing scanned values;
|
||||
* individual pointers may be NULL
|
||||
* @return Number of values scanned
|
||||
*
|
||||
*/
|
||||
BU_EXPORT extern int bu_scan_fastf_t(int *c, const char *src, const char *delim, size_t n, ...);
|
||||
|
||||
+14
-1
@@ -103,10 +103,23 @@ BU_EXPORT extern void bu_nice_set(int newnice);
|
||||
|
||||
/**
|
||||
* Return the maximum number of physical CPUs that are considered to
|
||||
* be available to this process now.
|
||||
* be available to this process now, subject to any process-local limit set by
|
||||
* bu_avail_cpus_set().
|
||||
*/
|
||||
BU_EXPORT extern size_t bu_avail_cpus(void);
|
||||
|
||||
/**
|
||||
* Limit the CPU count reported by bu_avail_cpus() and honored by subsequent
|
||||
* bu_parallel() calls in this process. A value of zero removes the limit.
|
||||
* Call this before starting worker threads; changing the limit does not resize
|
||||
* work that is already running.
|
||||
*
|
||||
* This is useful when several independent processes share one machine and
|
||||
* each process contains code that selects its own parallelism with
|
||||
* bu_avail_cpus().
|
||||
*/
|
||||
BU_EXPORT extern void bu_avail_cpus_set(size_t ncpu);
|
||||
|
||||
|
||||
/**
|
||||
* Create parallel threads of execution.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
45
|
||||
46
|
||||
|
||||
@@ -31,7 +31,10 @@
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
||||
struct rt_comb_internal; /* forward declaration */
|
||||
struct bu_external;
|
||||
struct db_i;
|
||||
struct directory;
|
||||
struct rt_comb_internal;
|
||||
|
||||
|
||||
/* db5_attr.c */
|
||||
|
||||
+2
-2
@@ -84,7 +84,7 @@ __BEGIN_DECLS
|
||||
#define RT_DEBUG_HF 0x04000000 /**< @brief 27 Height Field solids */
|
||||
|
||||
#define RT_DEBUG_MESHING 0x08000000 /**< @brief 28 Print meshing/triangulation details */
|
||||
#define RT_DEBUG_UNUSED_3 0x10000000 /**< @brief 29 Unassigned */
|
||||
#define RT_DEBUG_RTCMP 0x10000000 /**< @brief 29 Set up rtcmp capture; recording uses a runtime toggle. If LIBRT_RTCMP_PRIMITIVES=1 includes primitive segments. */
|
||||
#define RT_DEBUG_UNUSED_4 0x20000000 /**< @brief 30 Unassigned */
|
||||
|
||||
/* Options which will cause the library to write binary debugging output */
|
||||
@@ -96,7 +96,7 @@ __BEGIN_DECLS
|
||||
"\040PL_BOX" \
|
||||
"\037PL_SOLIDS" \
|
||||
"\036UNUSED_4" \
|
||||
"\035UNUSED_3" \
|
||||
"\035RTCMP" \
|
||||
"\034UNUSED_2" \
|
||||
"\033HF" \
|
||||
"\032EBM" \
|
||||
|
||||
+23
-6
@@ -465,6 +465,17 @@ rt_get_solid_keypoint(struct rt_edit *s, point_t *pt, const char **strp, fastf_t
|
||||
RT_EXPORT extern void
|
||||
rt_edit_set_edflag(struct rt_edit *s, int edflag);
|
||||
|
||||
/**
|
||||
* Set a parameter-edit translation target expressed in model base units.
|
||||
*
|
||||
* rt_edit's parameter-edit handlers consume e_para in database local units,
|
||||
* while keypoints and edit axes are maintained in model base units. This
|
||||
* helper performs the boundary conversion for callers that have computed a
|
||||
* target from a keypoint, axis, or view transform.
|
||||
*/
|
||||
RT_EXPORT extern void
|
||||
rt_edit_set_translation_target(struct rt_edit *s, const point_t target);
|
||||
|
||||
RT_EXPORT extern int
|
||||
rt_edit_knob_cmd_process(
|
||||
struct rt_edit *s,
|
||||
@@ -499,8 +510,10 @@ rt_knob_edit_sca(
|
||||
int matrix_edit);
|
||||
|
||||
/* Equivalent to sedit - run editing logic after input data is set in
|
||||
* rt_edit container */
|
||||
RT_EXPORT extern void
|
||||
* rt_edit container. Transient input flags are consumed whether the edit
|
||||
* succeeds or fails; parameter values remain available to the caller.
|
||||
* Returns BRLCAD_ERROR if the primitive edit fails. */
|
||||
RT_EXPORT extern int
|
||||
rt_edit_process(struct rt_edit *s);
|
||||
|
||||
/**
|
||||
@@ -521,7 +534,7 @@ rt_edit_snap_point(point2d_t pt, const struct rt_edit *s);
|
||||
* restored later with rt_edit_revert().
|
||||
*
|
||||
* The snapshot is stored inside the rt_edit struct. Calling this
|
||||
* function again overwrites any previous snapshot (single-level undo).
|
||||
* function again replaces the previous snapshot only on success.
|
||||
*
|
||||
* @return BRLCAD_OK on success, BRLCAD_ERROR if the export failed.
|
||||
*/
|
||||
@@ -532,8 +545,8 @@ rt_edit_checkpoint(struct rt_edit *s);
|
||||
* Restore primitive parameters from the snapshot saved by
|
||||
* rt_edit_checkpoint().
|
||||
*
|
||||
* If no snapshot has been saved (or the last snapshot was already
|
||||
* consumed) this function logs a message and returns BRLCAD_ERROR.
|
||||
* The snapshot remains available for repeated restores. If none has
|
||||
* been saved, this function logs a message and returns BRLCAD_ERROR.
|
||||
*
|
||||
* @return BRLCAD_OK on success, BRLCAD_ERROR otherwise.
|
||||
*/
|
||||
@@ -697,7 +710,11 @@ enum rt_constraint_edit_op_kind {
|
||||
RT_CONSTRAINT_EDIT_OP_SET_BEND,
|
||||
RT_CONSTRAINT_EDIT_OP_SCALE_OD,
|
||||
RT_CONSTRAINT_EDIT_OP_SCALE_ID,
|
||||
RT_CONSTRAINT_EDIT_OP_SCALE_BEND
|
||||
RT_CONSTRAINT_EDIT_OP_SCALE_BEND,
|
||||
/* Set every point when an all-zero dimension has no scale reference. */
|
||||
RT_CONSTRAINT_EDIT_OP_SET_ALL_OD,
|
||||
RT_CONSTRAINT_EDIT_OP_SET_ALL_ID,
|
||||
RT_CONSTRAINT_EDIT_OP_SET_ALL_BEND
|
||||
};
|
||||
|
||||
struct rt_constraint_edit_param_ref {
|
||||
|
||||
@@ -227,6 +227,32 @@ struct rt_crofton_params {
|
||||
double time_ms; /**< wall-clock time budget (ms); 0 = disabled */
|
||||
};
|
||||
|
||||
/** One solid partition observed by a Crofton ray. */
|
||||
struct rt_crofton_segment {
|
||||
point_t in_point;
|
||||
vect_t in_normal;
|
||||
point_t out_point;
|
||||
vect_t out_normal;
|
||||
fastf_t thickness;
|
||||
size_t ray_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structured samples and estimates produced by rt_crofton_collect().
|
||||
* Release @p segments with rt_crofton_result_free().
|
||||
*/
|
||||
struct rt_crofton_result {
|
||||
struct rt_crofton_segment *segments;
|
||||
size_t segment_count;
|
||||
size_t ray_count;
|
||||
size_t crossing_count;
|
||||
double surface_area;
|
||||
double volume;
|
||||
};
|
||||
|
||||
/** Initialize an rt_crofton_result before first use. */
|
||||
#define RT_CROFTON_RESULT_INIT { NULL, 0, 0, 0, 0.0, 0.0 }
|
||||
|
||||
|
||||
/**
|
||||
* Run the Cauchy-Crofton ray-sampling estimator on an already-prepared
|
||||
@@ -337,6 +363,26 @@ struct rt_crofton_params {
|
||||
*/
|
||||
RT_EXPORT extern int rt_crofton_shoot(double *out_surf_area, double *out_volume, point_t *out_aabb_min, point_t *out_aabb_max, point_t out_obb[8], point_t **out_points, size_t *out_point_count, struct rt_i *rtip, const struct rt_crofton_params *params, const fastf_t *bbox_min, const fastf_t *bbox_max);
|
||||
|
||||
/**
|
||||
* Run Crofton sampling while preserving oriented entry/exit pairs.
|
||||
*
|
||||
* @p result must be initialized with RT_CROFTON_RESULT_INIT. On success it
|
||||
* owns the returned segment array. @p rtip must already be prepared.
|
||||
* @p ray_offset skips that many samples in the deterministic sequence and
|
||||
* labels the returned rays starting at that value. This lets successive
|
||||
* calls use disjoint validation streams.
|
||||
*/
|
||||
RT_EXPORT extern int rt_crofton_collect(struct rt_crofton_result *result,
|
||||
struct rt_i *rtip,
|
||||
const struct rt_crofton_params *params,
|
||||
size_t ray_offset,
|
||||
const fastf_t *bbox_min,
|
||||
const fastf_t *bbox_max);
|
||||
|
||||
/** Release storage owned by a structured Crofton result. */
|
||||
RT_EXPORT extern void rt_crofton_result_free(
|
||||
struct rt_crofton_result *result);
|
||||
|
||||
|
||||
/**
|
||||
* Cauchy-Crofton surface-area and/or volume estimator for a primitive.
|
||||
|
||||
@@ -41,6 +41,7 @@ struct rt_nmg_edit {
|
||||
struct loopuse *lu_copy; /* copy of loop to be extruded */
|
||||
plane_t lu_pl; /* plane equation for loop to be extruded */
|
||||
struct shell *es_s; /* Shell where extrusion is to end up */
|
||||
int es_s_from_extrusion; /* Replace this edit's prior preview */
|
||||
point_t lu_keypoint; /* keypoint of lu_copy for extrusion */
|
||||
struct vertex *es_v; /* Currently selected NMG vertex (ECMD_NMG_VPICK) */
|
||||
struct faceuse *es_fu; /* Currently selected NMG faceuse (ECMD_NMG_FPICK) */
|
||||
|
||||
@@ -55,6 +55,18 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define RT_RTCMP_CAPTURE_RUNTIME_TOGGLE 1
|
||||
|
||||
/** Set RT_DEBUG_RTCMP recording: nonzero enables, zero disables.
|
||||
* Enabling requires the debug flag and a usable output writer.
|
||||
* Return 0 on success and -1 on failure. Disabling succeeds even
|
||||
* before setup.
|
||||
*/
|
||||
RT_EXPORT extern int rt_rtcmp_capture_set_enabled(int enabled);
|
||||
|
||||
/** Wait until pending RT_DEBUG_RTCMP records have reached the output file. */
|
||||
RT_EXPORT extern int rt_rtcmp_capture_flush(void);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Shoot a ray
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
include(CMakeParseArguments)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/BRLCAD_Repository.cmake")
|
||||
|
||||
# Try to locate a usable git executable. On Windows, Visual Studio may
|
||||
# provide git in non-standard locations; try common Program Files and
|
||||
@@ -88,6 +89,15 @@ function(brlcad_bext_init BEXT_SHA1)
|
||||
set(BRLCAD_EXT_DIR "${BRLCAD_EXT_DIR_ENV}")
|
||||
endif(BRLCAD_EXT_DIR_ENV AND NOT DEFINED BRLCAD_EXT_DIR)
|
||||
|
||||
# Resolve paths before probing them so later subconfigures use the same
|
||||
# directories even when launched from a different working directory.
|
||||
foreach(_brlcad_ext_path_var BRLCAD_EXT_DIR BRLCAD_EXT_SOURCE_DIR)
|
||||
if(DEFINED ${_brlcad_ext_path_var} AND NOT "${${_brlcad_ext_path_var}}" STREQUAL "")
|
||||
get_filename_component(${_brlcad_ext_path_var} "${${_brlcad_ext_path_var}}" ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
set(${_brlcad_ext_path_var} "${${_brlcad_ext_path_var}}" PARENT_SCOPE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(_brlcad_ext_dir_specified FALSE)
|
||||
set(_brlcad_ext_dir_managed FALSE)
|
||||
|
||||
@@ -148,14 +158,14 @@ function(brlcad_bext_init BEXT_SHA1)
|
||||
elseif(NOT _brlcad_ext_dir_specified)
|
||||
message(
|
||||
WARNING
|
||||
"External dependencies will be downloaded, configured, and built automatically as-needed. Set BRLCAD_EXT_DIR to specify instead."
|
||||
"External dependencies will be acquired from ${_BRLCAD_REPOSITORY_ROOT}, configured, and built automatically as-needed. Set BRLCAD_EXT_DIR to specify instead."
|
||||
)
|
||||
endif()
|
||||
message(
|
||||
STATUS
|
||||
"BRLCAD_EXT_DIR specifies prebuilt external dependencies directory\n"
|
||||
"containing 'install' and 'noinstall' folders, outputs from installing\n"
|
||||
"https://github.com/BRL-CAD/bext.\n"
|
||||
"${_BRLCAD_BEXT_REPOSITORY}.\n"
|
||||
)
|
||||
endif(NOT BRLCAD_EXT_NOINSTALL_DIR OR NOT BRLCAD_EXT_INSTALL_DIR)
|
||||
|
||||
@@ -211,28 +221,24 @@ function(brlcad_rel_version BRLCAD_REL)
|
||||
set(${BRLCAD_REL} "rel-${VMAJOR}-${VMINOR}-${VPATCH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Look up branch or tag SHA1 hashes from primary github.com repo
|
||||
# Branch/tag queries are advisory; an unavailable source cannot validate them.
|
||||
function(remote_sha1 SHA1_VAR BRANCH)
|
||||
set(${SHA1_VAR} "" PARENT_SCOPE)
|
||||
if(NOT GIT_EXEC)
|
||||
set(${SHA1_VAR} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
# This needs a working internet connection to succeed (and GitHub
|
||||
# must be up and working as well.)
|
||||
brlcad_repository_git_command(git_command)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXEC} ls-remote https://github.com/BRL-CAD/bext.git ${BRANCH}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
RESULT_VARIABLE LS_REMOTE_STATUS
|
||||
OUTPUT_VARIABLE LS_REMOTE_STR
|
||||
ERROR_VARIABLE LS_REMOTE_STR
|
||||
)
|
||||
if(NOT LS_REMOTE_STATUS AND LS_REMOTE_STR)
|
||||
string(REPLACE " " ";" LS_REMOTE_STR "${LS_REMOTE_STR}")
|
||||
string(REPLACE "\t" ";" LS_REMOTE_STR "${LS_REMOTE_STR}")
|
||||
list(GET LS_REMOTE_STR 0 REMOTE_SHA1)
|
||||
set(${SHA1_VAR} "${REMOTE_SHA1}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${SHA1_VAR} "" PARENT_SCOPE)
|
||||
COMMAND "${CMAKE_COMMAND}" -E env GIT_TERMINAL_PROMPT=0 --
|
||||
${git_command} -c credential.helper= -c credential.interactive=false
|
||||
ls-remote "${_BRLCAD_BEXT_REPOSITORY}" "${BRANCH}"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
RESULT_VARIABLE git_result
|
||||
OUTPUT_VARIABLE remote_refs
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(git_result STREQUAL "0" AND remote_refs MATCHES "^([0-9a-f]+)[ \t]")
|
||||
set(${SHA1_VAR} "${CMAKE_MATCH_1}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -367,24 +373,29 @@ function(setup_bext_dir)
|
||||
# no pre-existing sources, so we're cloning into the build dir
|
||||
set(BRLCAD_EXT_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/bext")
|
||||
|
||||
# Write current SHA1 for subsequent processing
|
||||
brlcad_repository_git_command(git_command)
|
||||
message(STATUS "Cloning bext from ${_BRLCAD_BEXT_REPOSITORY}")
|
||||
execute_process(
|
||||
COMMAND ${git_command} clone "${_BRLCAD_BEXT_REPOSITORY}" "${BRLCAD_EXT_SOURCE_DIR}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
RESULT_VARIABLE git_result
|
||||
)
|
||||
if(NOT git_result STREQUAL "0")
|
||||
message(FATAL_ERROR "Unable to clone bext from ${_BRLCAD_BEXT_REPOSITORY} (${git_result})")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${git_command} -c advice.detachedHead=false checkout "${BEXT_SHA1}"
|
||||
WORKING_DIRECTORY "${BRLCAD_EXT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE git_result
|
||||
)
|
||||
if(NOT git_result STREQUAL "0")
|
||||
message(FATAL_ERROR "Unable to check out pinned bext commit ${BEXT_SHA1} from ${_BRLCAD_BEXT_REPOSITORY} (${git_result}); ensure the repository contains this commit")
|
||||
endif()
|
||||
|
||||
# Record the pin only after checkout succeeds.
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/bext.sha1" "${BEXT_SHA1}")
|
||||
distclean("${CMAKE_CURRENT_BINARY_DIR}/bext.sha1")
|
||||
|
||||
# Clone
|
||||
message("BRL-CAD bext clone command: ${GIT_EXEC} clone https://github.com/BRL-CAD/bext.git")
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXEC} clone https://github.com/BRL-CAD/bext.git
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
)
|
||||
message("BRL-CAD bext checkout command: ${GIT_EXEC} -c advice.detachedHead=false checkout ${BEXT_SHA1}")
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXEC} -c advice.detachedHead=false checkout ${BEXT_SHA1}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bext
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
)
|
||||
|
||||
# Configure process will need to clean up bext
|
||||
if (BRLCAD_BEXT_CLEANUP)
|
||||
set(BEXT_SRC_CLEANUP TRUE PARENT_SCOPE)
|
||||
@@ -425,6 +436,12 @@ function(brlcad_ext_setup)
|
||||
message(FATAL_ERROR "Invalid bext directory: ${BRLCAD_EXT_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
if(NOT _BRLCAD_REPOSITORY_ROOT STREQUAL "${_BRLCAD_REPOSITORY_DEFAULT_ROOT}/"
|
||||
AND NOT EXISTS "${BRLCAD_EXT_SOURCE_DIR}/CMake/BextGit.cmake")
|
||||
message(FATAL_ERROR
|
||||
"bext sources in ${BRLCAD_EXT_SOURCE_DIR} do not support BEXT_REPOSITORY_ROOT; update bext before building with BRLCAD_REPOSITORY_ROOT=${BRLCAD_REPOSITORY_ROOT}")
|
||||
endif()
|
||||
|
||||
# We do allow the user to specify a build dir to be reused, however
|
||||
# this is unpredictable and may cause unexpected results depending
|
||||
# on what is or isn't rebuilt - use with care.
|
||||
@@ -463,11 +480,18 @@ function(brlcad_ext_setup)
|
||||
endif(BRLCAD_ENABLE_APPLESEED)
|
||||
|
||||
# Define CMake arguments we'll need regardless of mode
|
||||
set(bext_shallow_clone ON)
|
||||
if(_BRLCAD_REPOSITORY_LOCAL)
|
||||
set(bext_shallow_clone OFF)
|
||||
endif()
|
||||
set(CMAKE_CMD_ARGS
|
||||
-S ${BRLCAD_EXT_SOURCE_DIR} -B ${BRLCAD_EXT_BUILD_DIR} -DGIT_SHALLOW_CLONE=ON
|
||||
-DENABLE_ALL=${BEXT_ENABLE_ALL} -DUSE_GDAL=${BEXT_USE_GDAL} -DUSE_QT=${BEXT_USE_QT} -DUSE_TCL=${BEXT_USE_TCL}
|
||||
-DUSE_APPLESEED=${BEXT_USE_APPLESEED} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
-DCMAKE_INSTALL_PREFIX=${BRLCAD_EXT_INSTALL_DIR}
|
||||
-S "${BRLCAD_EXT_SOURCE_DIR}" -B "${BRLCAD_EXT_BUILD_DIR}"
|
||||
"-DBEXT_REPOSITORY_ROOT:STRING=${_BRLCAD_REPOSITORY_ROOT}"
|
||||
"-DGIT_SHALLOW_CLONE:BOOL=${bext_shallow_clone}"
|
||||
"-DENABLE_ALL=${BEXT_ENABLE_ALL}" "-DUSE_GDAL=${BEXT_USE_GDAL}"
|
||||
"-DUSE_QT=${BEXT_USE_QT}" "-DUSE_TCL=${BEXT_USE_TCL}"
|
||||
"-DUSE_APPLESEED=${BEXT_USE_APPLESEED}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
|
||||
"-DCMAKE_INSTALL_PREFIX=${BRLCAD_EXT_INSTALL_DIR}"
|
||||
)
|
||||
if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND BRLCAD_XMIN_ROOT)
|
||||
list(APPEND CMAKE_CMD_ARGS
|
||||
|
||||
@@ -119,14 +119,16 @@ mark_as_advanced(SYS_INCLUDE_PATTERNS)
|
||||
# ${BRLCAD_EXT_DIR}/install copies, so wrap logic to do so into a
|
||||
# function.
|
||||
function(strip_excluded RDIR EXPATTERNS)
|
||||
file(GLOB_RECURSE staged_files LIST_DIRECTORIES false RELATIVE "${RDIR}" "${RDIR}/*")
|
||||
foreach(ep ${${EXPATTERNS}})
|
||||
file(GLOB_RECURSE MATCHING_FILES LIST_DIRECTORIES false RELATIVE "${RDIR}" "${RDIR}/${ep}")
|
||||
foreach(rf ${MATCHING_FILES})
|
||||
set(matching_files ${staged_files})
|
||||
list(FILTER matching_files INCLUDE REGEX "${ep}")
|
||||
foreach(rf ${matching_files})
|
||||
file(REMOVE "${RDIR}/${rf}")
|
||||
if(EXISTS ${RDIR}/${rf})
|
||||
if(EXISTS "${RDIR}/${rf}")
|
||||
message(FATAL_ERROR "Removing ${RDIR}/${rf} failed")
|
||||
endif(EXISTS ${RDIR}/${rf})
|
||||
endforeach(rf ${MATCHING_FILES})
|
||||
endif(EXISTS "${RDIR}/${rf}")
|
||||
endforeach(rf ${matching_files})
|
||||
endforeach(ep ${${EXPATTERNS}})
|
||||
endfunction(strip_excluded)
|
||||
|
||||
@@ -1106,9 +1108,9 @@ function(brlcad_install_strclear_replace stamp_dir strclear source install_file
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(brlcad_install_binary_postprocess stamp_dir strclear source install_file install_type mode rpath_tool install_rpath build_lib_path rel_rpath use_selective_rpath verbose)
|
||||
function(brlcad_install_binary_postprocess stamp_dir strclear source install_file install_type mode rpath_tool install_rpath build_lib_path rel_rpath verbose)
|
||||
set(_brlcad_physical_file "$ENV{DESTDIR}${install_file}")
|
||||
set(_brlcad_signature "binary-postprocess|${install_type}|${mode}|${rpath_tool}|${install_rpath}|${build_lib_path}|${rel_rpath}|${use_selective_rpath}|${strclear}")
|
||||
set(_brlcad_signature "binary-postprocess|${install_type}|${mode}|${rpath_tool}|${install_rpath}|${build_lib_path}|${rel_rpath}|${strclear}")
|
||||
_brlcad_postprocess_needed(_brlcad_needed "${stamp_dir}" "${source}" "${_brlcad_physical_file}" "${_brlcad_signature}")
|
||||
if(NOT _brlcad_needed)
|
||||
return()
|
||||
@@ -1119,32 +1121,41 @@ function(brlcad_install_binary_postprocess stamp_dir strclear source install_fil
|
||||
message(FATAL_ERROR "Post-install copy did not create ${_brlcad_physical_file}")
|
||||
endif()
|
||||
set(_brlcad_result 0)
|
||||
set(_brlcad_rpath_output)
|
||||
set(_brlcad_rpath_error)
|
||||
if("${mode}" STREQUAL "RPATH_TOOL")
|
||||
set(_brlcad_selective_rpath_args)
|
||||
if(use_selective_rpath)
|
||||
set(_brlcad_selective_rpath_args --set-rpath-if-needed --set-rpath-if-needed-prepend --stale-rpath-prefix "${build_lib_path}")
|
||||
endif()
|
||||
# Install the exact project-defined search order. A selective update can
|
||||
# leave an existing relative-only RPATH without the canonical install path.
|
||||
execute_process(
|
||||
COMMAND "${rpath_tool}" --set-rpath "${install_rpath}" ${_brlcad_selective_rpath_args} "${_brlcad_physical_file}"
|
||||
COMMAND "${rpath_tool}" --set-rpath "${install_rpath}" "${_brlcad_physical_file}"
|
||||
RESULT_VARIABLE _brlcad_result
|
||||
OUTPUT_VARIABLE _brlcad_rpath_output
|
||||
ERROR_VARIABLE _brlcad_rpath_error
|
||||
)
|
||||
elseif("${mode}" STREQUAL "APPLE")
|
||||
execute_process(
|
||||
COMMAND install_name_tool -delete_rpath "${build_lib_path}" "${_brlcad_physical_file}"
|
||||
RESULT_VARIABLE _brlcad_result
|
||||
OUTPUT_VARIABLE _brlcad_output
|
||||
ERROR_VARIABLE _brlcad_error
|
||||
OUTPUT_VARIABLE _brlcad_rpath_output
|
||||
ERROR_VARIABLE _brlcad_rpath_error
|
||||
)
|
||||
if(_brlcad_result EQUAL 0)
|
||||
execute_process(
|
||||
COMMAND install_name_tool -add_rpath "${rel_rpath}" "${_brlcad_physical_file}"
|
||||
RESULT_VARIABLE _brlcad_result
|
||||
OUTPUT_VARIABLE _brlcad_rpath_output
|
||||
ERROR_VARIABLE _brlcad_rpath_error
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT _brlcad_result EQUAL 0)
|
||||
message(WARNING "Post-install RPATH update failed for ${_brlcad_physical_file}")
|
||||
message(
|
||||
WARNING
|
||||
"Post-install RPATH update failed for ${_brlcad_physical_file}\n"
|
||||
"stdout: ${_brlcad_rpath_output}\n"
|
||||
"stderr: ${_brlcad_rpath_error}"
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
@@ -1838,13 +1849,9 @@ endfunction()
|
||||
elseif(APPLE)
|
||||
set(_brlcad_install_postprocess_mode "APPLE")
|
||||
endif(P_RPATH_EXECUTABLE)
|
||||
set(_brlcad_install_use_selective_rpath FALSE)
|
||||
if(P_RPATH_SUPPORTS_SET_IF_NEEDED_PREPEND)
|
||||
set(_brlcad_install_use_selective_rpath TRUE)
|
||||
endif(P_RPATH_SUPPORTS_SET_IF_NEEDED_PREPEND)
|
||||
install(
|
||||
CODE
|
||||
"include(\"${BRLCAD_EXT_INSTALL_POSTPROCESS_SCRIPT}\")\nbrlcad_install_binary_postprocess(\"${BRLCAD_EXT_INSTALL_POSTPROCESS_STAMP_DIR}\" \"${STRCLEAR_EXECUTABLE}\" \"${CMAKE_BINARY_DIR}/${tf}\" \"\${CMAKE_INSTALL_PREFIX}/${tf}\" \"PROGRAM\" \"${_brlcad_install_postprocess_mode}\" \"${_brlcad_install_postprocess_tool}\" \"${_brlcad_install_postprocess_rpath}\" \"${CMAKE_BINARY_DIR}/${LIB_DIR}\" \"${REL_RPATH}\" \"${_brlcad_install_use_selective_rpath}\" \"${BRLCAD_VERBOSE}\")"
|
||||
"include(\"${BRLCAD_EXT_INSTALL_POSTPROCESS_SCRIPT}\")\nbrlcad_install_binary_postprocess(\"${BRLCAD_EXT_INSTALL_POSTPROCESS_STAMP_DIR}\" \"${STRCLEAR_EXECUTABLE}\" \"${CMAKE_BINARY_DIR}/${tf}\" \"\${CMAKE_INSTALL_PREFIX}/${tf}\" \"PROGRAM\" \"${_brlcad_install_postprocess_mode}\" \"${_brlcad_install_postprocess_tool}\" \"${_brlcad_install_postprocess_rpath}\" \"${CMAKE_BINARY_DIR}/${LIB_DIR}\" \"${REL_RPATH}\" \"${BRLCAD_VERBOSE}\")"
|
||||
)
|
||||
continue()
|
||||
endif("${tf}" IN_LIST ALL_BINARY_FILES)
|
||||
@@ -2198,7 +2205,11 @@ macro(find_package_opencv)
|
||||
set(OpenCV_DIR_TMP "${OpenCV_DIR}")
|
||||
set(OpenCV_DIR "${CMAKE_BINARY_DIR}/${LIB_DIR}/cmake/opencv4")
|
||||
set(OpenCV_ROOT ${CMAKE_BINARY_DIR})
|
||||
find_package(OpenCV COMPONENTS core features2d imgproc highgui)
|
||||
find_package(OpenCV CONFIG COMPONENTS core imgproc imgcodecs highgui)
|
||||
if(OpenCV_FOUND AND OpenCV_VERSION_MAJOR GREATER_EQUAL 5)
|
||||
# OpenCV 5 moved boundingRect from imgproc to geometry.
|
||||
find_package(OpenCV CONFIG COMPONENTS geometry)
|
||||
endif()
|
||||
unset(OpenCV_ROOT)
|
||||
|
||||
# If no bundled copy, see what the system has
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# Copyright (c) 2026 United States Government as represented by
|
||||
# the U.S. Army Research Laboratory.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# 3. The name of the author may not be used to endorse or promote
|
||||
# products derived from this software without specific prior written
|
||||
# permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
include_guard(GLOBAL)
|
||||
|
||||
set(_BRLCAD_REPOSITORY_DEFAULT_ROOT "https://github.com/BRL-CAD")
|
||||
set(BRLCAD_REPOSITORY_ROOT "${_BRLCAD_REPOSITORY_DEFAULT_ROOT}" CACHE STRING
|
||||
"Repository URL or local mirror directory containing bext and its dependency repositories")
|
||||
|
||||
function(brlcad_repository_root out_root out_local)
|
||||
set(root "${BRLCAD_REPOSITORY_ROOT}")
|
||||
set(local FALSE)
|
||||
if(root STREQUAL "")
|
||||
message(FATAL_ERROR "BRLCAD_REPOSITORY_ROOT must be a repository URL or local mirror directory")
|
||||
endif()
|
||||
|
||||
# Match bext's URL handling, but resolve relative paths against BRL-CAD.
|
||||
# Drive paths must be checked before scp-style SSH locations.
|
||||
if(root MATCHES "^file://")
|
||||
set(local TRUE)
|
||||
string(REPLACE "=" "%3D" root "${root}")
|
||||
elseif(root MATCHES "^[A-Za-z]:[/\\\\]" OR
|
||||
NOT (root MATCHES "^[A-Za-z][A-Za-z0-9+.-]*://" OR root MATCHES "^[^/]+:.+"))
|
||||
set(local TRUE)
|
||||
string(REPLACE "\\" "/" root "${root}")
|
||||
if(WIN32 OR NOT root MATCHES "^[A-Za-z]:/")
|
||||
get_filename_component(root "${root}" ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif()
|
||||
# Escape literal percent signs first so native paths cannot introduce
|
||||
# URL escapes. An equals sign also has meaning in Git's -c assignments.
|
||||
string(REPLACE "%" "%25" root "${root}")
|
||||
string(REPLACE " " "%20" root "${root}")
|
||||
string(REPLACE "#" "%23" root "${root}")
|
||||
string(REPLACE "?" "%3F" root "${root}")
|
||||
string(REPLACE "=" "%3D" root "${root}")
|
||||
if(root MATCHES "^[A-Za-z]:/")
|
||||
set(root "file:///${root}")
|
||||
elseif(root MATCHES "^//")
|
||||
set(root "file:${root}")
|
||||
else()
|
||||
set(root "file://${root}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT root MATCHES "^file:///*$")
|
||||
string(REGEX REPLACE "/+$" "" root "${root}")
|
||||
string(APPEND root "/")
|
||||
else()
|
||||
set(root "file:///")
|
||||
endif()
|
||||
set(${out_root} "${root}" PARENT_SCOPE)
|
||||
set(${out_local} "${local}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(brlcad_repository_git_command out_command)
|
||||
set(git_command "${GIT_EXEC}")
|
||||
if(WIN32)
|
||||
list(APPEND git_command -c core.longpaths=true)
|
||||
endif()
|
||||
if(_BRLCAD_REPOSITORY_LOCAL)
|
||||
list(APPEND git_command -c protocol.file.allow=always)
|
||||
# This also constrains recursive Git processes and user URL rewrites.
|
||||
list(PREPEND git_command "${CMAKE_COMMAND}" -E env GIT_ALLOW_PROTOCOL=file --)
|
||||
endif()
|
||||
set(${out_command} "${git_command}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
brlcad_repository_root(_BRLCAD_REPOSITORY_ROOT _BRLCAD_REPOSITORY_LOCAL)
|
||||
set(_BRLCAD_BEXT_REPOSITORY "${_BRLCAD_REPOSITORY_ROOT}bext.git")
|
||||
message(STATUS "BRL-CAD repository root: ${_BRLCAD_REPOSITORY_ROOT}")
|
||||
if(_BRLCAD_REPOSITORY_LOCAL)
|
||||
message(STATUS "BRL-CAD Git acquisition: file transport only")
|
||||
endif()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width: 8
|
||||
# mode: cmake
|
||||
# indent-tabs-mode: t
|
||||
# End:
|
||||
# ex: shiftwidth=2 tabstop=8
|
||||
@@ -169,23 +169,26 @@ function(BRLCAD_ADD_TEST NAME test_name COMMAND test_prog)
|
||||
add_dependencies(check ${_test_dependencies})
|
||||
endfunction(BRLCAD_ADD_TEST)
|
||||
|
||||
# Register a test whose command needs a private X server. Keeping Xmin's
|
||||
# process setup here lets GUI fixtures concentrate on application behavior and
|
||||
# gives every caller the same display geometry, timeout, and dependency
|
||||
# handling. Tests are registered only when the build selected Xmin as its X11
|
||||
# provider.
|
||||
function(BRLCAD_ADD_XMIN_TEST)
|
||||
if(NOT BUILD_TESTING OR NOT BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN")
|
||||
# Register a GUI test using the selected display backend. Xmin is currently
|
||||
# the only backend; its server and control paths stay here so fixtures only
|
||||
# depend on the GUI test controller contract.
|
||||
function(BRLCAD_ADD_GUI_TEST)
|
||||
if(NOT BUILD_TESTING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_parse_arguments(PARSE_ARGV 0 XMIN "" "NAME;SCREEN;TIMEOUT"
|
||||
"COMMAND;ENVIRONMENT;SERVER_ARGS")
|
||||
if(NOT XMIN_NAME)
|
||||
message(FATAL_ERROR "BRLCAD_ADD_XMIN_TEST requires NAME")
|
||||
if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN")
|
||||
_brlcad_add_xmin_gui_test(${ARGV})
|
||||
endif()
|
||||
if(NOT XMIN_COMMAND)
|
||||
message(FATAL_ERROR "BRLCAD_ADD_XMIN_TEST requires COMMAND")
|
||||
endfunction()
|
||||
|
||||
function(_brlcad_add_xmin_gui_test)
|
||||
cmake_parse_arguments(PARSE_ARGV 0 GUI "" "NAME;SCREEN;TIMEOUT"
|
||||
"COMMAND;ENVIRONMENT;SERVER_ARGS")
|
||||
if(NOT GUI_NAME)
|
||||
message(FATAL_ERROR "BRLCAD_ADD_GUI_TEST requires NAME")
|
||||
endif()
|
||||
if(NOT GUI_COMMAND)
|
||||
message(FATAL_ERROR "BRLCAD_ADD_GUI_TEST requires COMMAND")
|
||||
endif()
|
||||
|
||||
set(_xmin_server "${Xmin_SERVER_EXECUTABLE}")
|
||||
@@ -199,36 +202,42 @@ function(BRLCAD_ADD_XMIN_TEST)
|
||||
find_program(_xmin_run NAMES xmin-run HINTS "${_xmin_bin_dir}" NO_DEFAULT_PATH NO_CACHE)
|
||||
endif()
|
||||
if(NOT _xmin_server OR NOT _xmin_run)
|
||||
message(WARNING "Skipping ${XMIN_NAME}: the selected Xmin SDK does not provide its test runner")
|
||||
message(WARNING "Skipping ${GUI_NAME}: the selected Xmin SDK does not provide its test runner")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT XMIN_SCREEN)
|
||||
set(XMIN_SCREEN "1280x960x24")
|
||||
if(NOT GUI_SCREEN)
|
||||
set(GUI_SCREEN "1280x960x24")
|
||||
endif()
|
||||
if(NOT _xmin_bin_dir)
|
||||
get_filename_component(_xmin_bin_dir "${_xmin_server}" DIRECTORY)
|
||||
endif()
|
||||
find_program(_xmin_ctl NAMES xminctl HINTS "${_xmin_bin_dir}"
|
||||
NO_DEFAULT_PATH NO_CACHE)
|
||||
|
||||
set(_xmin_environment "XMIN_SCREEN=${XMIN_SCREEN}" ${XMIN_ENVIRONMENT})
|
||||
set(_gui_environment
|
||||
"GUI_TEST_SCREEN=${GUI_SCREEN}"
|
||||
"XMIN_SCREEN=${GUI_SCREEN}"
|
||||
${GUI_ENVIRONMENT}
|
||||
)
|
||||
if(_xmin_ctl)
|
||||
list(PREPEND _xmin_environment "XMIN_CTL=${_xmin_ctl}")
|
||||
list(PREPEND _gui_environment
|
||||
"GUI_TEST_CTL=${CMAKE_SOURCE_DIR}/regress/xmin/xmin_gui_ctl.sh"
|
||||
"XMIN_CTL=${_xmin_ctl}"
|
||||
)
|
||||
endif()
|
||||
set(_xmin_command
|
||||
"${CMAKE_COMMAND}" -E env ${_xmin_environment} ${XMIN_COMMAND}
|
||||
set(_gui_command
|
||||
"${CMAKE_COMMAND}" -E env ${_gui_environment} ${GUI_COMMAND}
|
||||
)
|
||||
|
||||
brlcad_add_test(
|
||||
NAME ${XMIN_NAME}
|
||||
NAME ${GUI_NAME}
|
||||
COMMAND "${_xmin_run}" --server "${_xmin_server}"
|
||||
--screen "${XMIN_SCREEN}" ${XMIN_SERVER_ARGS} -- ${_xmin_command}
|
||||
--screen "${GUI_SCREEN}" ${GUI_SERVER_ARGS} -- ${_gui_command}
|
||||
)
|
||||
if(XMIN_TIMEOUT)
|
||||
set_tests_properties(${XMIN_NAME} PROPERTIES TIMEOUT "${XMIN_TIMEOUT}")
|
||||
if(GUI_TIMEOUT)
|
||||
set_tests_properties(${GUI_NAME} PROPERTIES TIMEOUT "${GUI_TIMEOUT}")
|
||||
endif()
|
||||
endfunction(BRLCAD_ADD_XMIN_TEST)
|
||||
endfunction()
|
||||
|
||||
# Local Variables:
|
||||
# mode: cmake
|
||||
|
||||
@@ -15,6 +15,7 @@ set(
|
||||
BRLCAD_Options.cmake
|
||||
BRLCAD_Probe_Validation.cmake
|
||||
BRLCAD_Regress_Util.cmake
|
||||
BRLCAD_Repository.cmake
|
||||
BRLCAD_Summary.cmake
|
||||
BRLCAD_Targets.cmake
|
||||
BRLCAD_Test_Wrappers.cmake
|
||||
|
||||
@@ -95,6 +95,33 @@ add_custom_target(
|
||||
)
|
||||
set_target_properties(distcheck-source_archives PROPERTIES FOLDER "BRL-CAD Distribution Checking")
|
||||
|
||||
# Dependency paths must survive CMake, build-tool, and shell parsing. Load
|
||||
# their values from a cache file rather than embedding them in command text.
|
||||
set(distcheck_dependency_cache "${CMAKE_CURRENT_BINARY_DIR}/CMakeTmp/distcheck_dependencies.cmake")
|
||||
set(distcheck_dependency_vars BRLCAD_REPOSITORY_ROOT BRLCAD_EXT_DIR)
|
||||
foreach(distcheck_optional_var BRLCAD_EXT_SOURCE_DIR BRLCAD_EXT_PARALLEL)
|
||||
if(DEFINED ${distcheck_optional_var})
|
||||
list(APPEND distcheck_dependency_vars ${distcheck_optional_var})
|
||||
endif()
|
||||
endforeach()
|
||||
file(WRITE "${distcheck_dependency_cache}" "")
|
||||
foreach(distcheck_var IN LISTS distcheck_dependency_vars)
|
||||
set(distcheck_value "${${distcheck_var}}")
|
||||
if(distcheck_var STREQUAL "BRLCAD_REPOSITORY_ROOT")
|
||||
set(distcheck_value "${_BRLCAD_REPOSITORY_ROOT}")
|
||||
endif()
|
||||
set(distcheck_type STRING)
|
||||
if(distcheck_var MATCHES "_DIR$")
|
||||
set(distcheck_type PATH)
|
||||
endif()
|
||||
string(REPLACE "\\" "\\\\" distcheck_value "${distcheck_value}")
|
||||
string(REPLACE "\"" "\\\"" distcheck_value "${distcheck_value}")
|
||||
string(REPLACE "$" "\\$" distcheck_value "${distcheck_value}")
|
||||
file(APPEND "${distcheck_dependency_cache}"
|
||||
"set(${distcheck_var} \"${distcheck_value}\" CACHE ${distcheck_type} \"Inherited dependency setting\" FORCE)\n")
|
||||
endforeach()
|
||||
distclean("${distcheck_dependency_cache}")
|
||||
|
||||
# Utility function for defining individual distcheck targets
|
||||
macro(
|
||||
create_distcheck
|
||||
@@ -120,7 +147,10 @@ macro(
|
||||
|
||||
# Need to set these locally so configure_file will pick them up...
|
||||
set(TARGET_SUFFIX ${TARGET_SUFFIX})
|
||||
set(CMAKE_OPTS ${CMAKE_OPTS_IN})
|
||||
# Keep machine-specific settings out of the options saved for CI above.
|
||||
# The shared cache replaces each variant's unquoted output argument.
|
||||
string(REPLACE "-DBRLCAD_EXT_DIR=${BRLCAD_EXT_DIR}" "" CMAKE_OPTS "${CMAKE_OPTS_IN}")
|
||||
string(APPEND CMAKE_OPTS " -C \"${distcheck_dependency_cache}\"")
|
||||
|
||||
# For configure_file, need to set these as variables not just input parameters
|
||||
set(source_dir "${source_dir}")
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
brlcad (7.46.0-0) unstable; urgency=low
|
||||
|
||||
* update brlcad version
|
||||
|
||||
-- Cliff Yapp <cyapp@brlcad.org> Thu, 07 Oct 2026 20:24:00 +0000
|
||||
|
||||
brlcad (7.44.0-0) unstable; urgency=low
|
||||
|
||||
* update brlcad version
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
\f0\i\b\fs72 \cf0 README
|
||||
\fs36 \
|
||||
|
||||
\f1\i0\b0\fs28 This is BRL-CAD 7.44.0 for Mac OS X. Please send any bugs, comments, questions, or suggestions to the project website.\
|
||||
\f1\i0\b0\fs28 This is BRL-CAD 7.46.0 for Mac OS X. Please send any bugs, comments, questions, or suggestions to the project website.\
|
||||
|
||||
\fs22 \
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
\margl1440\margr1440\vieww8020\viewh6280\viewkind0
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
|
||||
|
||||
\f0\fs22 \cf0 This installer will guide you through the installation of BRL-CAD 7.44.0 for Mac OS X and Darwin.\
|
||||
\f0\fs22 \cf0 This installer will guide you through the installation of BRL-CAD 7.46.0 for Mac OS X and Darwin.\
|
||||
\
|
||||
This distribution of BRL-CAD requires approximately 500 MB of available disk space and does not include source code.\
|
||||
\
|
||||
|
||||
@@ -110,7 +110,8 @@ add_subdirectory(rtedge)
|
||||
# RtWizard Image Generation Regression Tests
|
||||
add_subdirectory(rtwizard)
|
||||
|
||||
# Shared Xmin GUI test support
|
||||
# Shared GUI test support and Xmin fixtures
|
||||
add_subdirectory(gui)
|
||||
add_subdirectory(xmin)
|
||||
|
||||
# per-primitive validity
|
||||
|
||||
@@ -117,6 +117,20 @@ if(TARGET libged)
|
||||
|
||||
endif(TARGET libged)
|
||||
|
||||
if(TARGET librt AND FUZZER_SUPPORTED)
|
||||
set(RT_EDIT_FUZZ_DIR "${CMAKE_SOURCE_DIR}/src/librt/tests/edit")
|
||||
brlcad_addexec(
|
||||
fuzz_rt_edit_test
|
||||
"${RT_EDIT_FUZZ_DIR}/fuzz.cpp;${RT_EDIT_FUZZ_DIR}/ars.cpp;${RT_EDIT_FUZZ_DIR}/bot.cpp"
|
||||
"libbu;librt;libnmg;libwdb;libbrep"
|
||||
TEST
|
||||
)
|
||||
set_target_properties(fuzz_rt_edit_test PROPERTIES UNITY_BUILD OFF)
|
||||
target_compile_options(fuzz_rt_edit_test PRIVATE ${FUZZER_EXE_COMPILE_OPTIONS})
|
||||
target_link_options(fuzz_rt_edit_test PRIVATE ${FUZZER_LINK_OPTIONS})
|
||||
BRLCAD_ADD_TEST(NAME fuzz_rt_edit_smoke COMMAND fuzz_rt_edit_test -runs=1 -max_total_time=5)
|
||||
endif()
|
||||
|
||||
cmakefiles(
|
||||
CMakeLists.txt
|
||||
fuzz_ged.cpp
|
||||
|
||||
+13
-17
@@ -79,7 +79,9 @@ endif(NOT EXISTS \"\${GCV_EXEC}\")\n"
|
||||
# setup conversion tests
|
||||
foreach(in_file ${INPUT_FILES})
|
||||
get_filename_component(curr_in_basename ${in_file} NAME_WLE)
|
||||
set(out_path "${CMAKE_CURRENT_BINARY_DIR}/conv-${curr_in_basename}")
|
||||
# Tests in the same directory may run concurrently, so their output paths
|
||||
# must not overlap.
|
||||
set(out_path "${CMAKE_CURRENT_BINARY_DIR}/conv-${TARGET_DIRECTION}-${curr_in_basename}")
|
||||
|
||||
# need to split suffix so we can distinguish from different converters
|
||||
if(${fmt}_EXPORTER)
|
||||
@@ -120,7 +122,7 @@ endif(NOT EXISTS \"\${GCV_EXEC}\")\n"
|
||||
)
|
||||
endif(${fmt}_GCV_OPTIONS)
|
||||
|
||||
set(out_distclean ${out_distclean}} "${out_path}-${out_fmt}${out_suffix}")
|
||||
set(out_distclean ${out_distclean} "${out_path}-${out_fmt}${out_suffix}")
|
||||
set(expected_output_files "${expected_output_files} \"${out_path}-${out_fmt}${out_suffix}\"")
|
||||
endforeach(out_fmt ${${fmt}_CONVERTERS})
|
||||
|
||||
@@ -162,19 +164,8 @@ execute_process(
|
||||
|
||||
file(APPEND \"\${LOGFILE}\" \"\${log_msg}\\n\")
|
||||
unset(log_msg)
|
||||
"
|
||||
)
|
||||
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} ${out_distclean})
|
||||
unset(expected_output_files)
|
||||
unset(out_distclean)
|
||||
endforeach(in_file ${INPUT_FILES})
|
||||
|
||||
file(
|
||||
APPEND
|
||||
${cmake_in_path}
|
||||
"
|
||||
# check output files exists and are a reasonable size
|
||||
# check output files exist and are a reasonable size
|
||||
foreach(out_file \${ofiles})
|
||||
if(NOT EXISTS \"\${out_file}\")
|
||||
file(APPEND \"\${LOGFILE}\" \"FAILURE: \${curr_result}, \${out_file} not found.\")
|
||||
@@ -191,13 +182,18 @@ foreach(out_file \${ofiles})
|
||||
file(APPEND \"\${LOGFILE}\" \"FAILURE: \${curr_result} file size is \${file_size} for \${out_file}\\n Expecting ${EXPECTED_FILE_SIZE} with delta ${FILE_SIZE_DELTA}\")
|
||||
message(FATAL_ERROR \"[gcv] Failure while converting ${in_file}, see \${LOGFILE} for more info.\")
|
||||
endif(\"\${size_delta}\" GREATER \"${FILE_SIZE_DELTA}\")
|
||||
endif(NOT EXISTS \"\${out_file}\")\n
|
||||
endif(NOT EXISTS \"\${out_file}\")
|
||||
|
||||
# cleanup file from build dir
|
||||
file(REMOVE \"\${out_file}\")
|
||||
endforeach(out_file \${ofiles})
|
||||
"
|
||||
)
|
||||
"
|
||||
)
|
||||
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} ${out_distclean})
|
||||
unset(expected_output_files)
|
||||
unset(out_distclean)
|
||||
endforeach(in_file ${INPUT_FILES})
|
||||
|
||||
# assume the fmt is the gcv dependency unless specified
|
||||
if(${fmt}_DEPS)
|
||||
|
||||
@@ -2,7 +2,7 @@ if(TARGET gcv-assetimport)
|
||||
gcv_regress_util("gltf" "tetra-gltf2.0.gltf;tetra-glb2.0.glb" DEPS "gcv;gcv-assetimport" GCV_OPTIONS "--input-format=assetimport")
|
||||
gcv_regress_util("glb" "tetra.g" DEPS "gcv;gcv-assetimport" GCV_OPTIONS "--output-format=assetimport" EXPECTED_FILE_SIZE "1476" EXPORTER)
|
||||
gcv_regress_util("gltf" "tetra.g" DEPS "gcv;gcv-assetimport" GCV_OPTIONS "--output-format=assetimport" EXPECTED_FILE_SIZE "3356" EXPORTER)
|
||||
distclean("${CMAKE_CURRENT_BINARY_DIR}/conv-tetra.bin")
|
||||
distclean("${CMAKE_CURRENT_BINARY_DIR}/conv-regress-g-gltf-tetra.bin")
|
||||
endif(TARGET gcv-assetimport)
|
||||
|
||||
if(TARGET gcv-gltf)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
if(TARGET gcv-assetimport)
|
||||
set(dep_str DEPS "gcv;gcv-obj;gcv-assetimport" CONVERTERS "assetimport")
|
||||
|
||||
distclean("${CMAKE_CURRENT_BINARY_DIR}/conv-tetra-assetimport.mtl") # hard to track companion files
|
||||
distclean("${CMAKE_CURRENT_BINARY_DIR}/conv-regress-g-obj-tetra-assetimport.mtl") # hard to track companion files
|
||||
else()
|
||||
set(dep_str "")
|
||||
endif(TARGET gcv-assetimport)
|
||||
@@ -9,7 +9,7 @@ endif(TARGET gcv-assetimport)
|
||||
gcv_regress_util("obj" "tetra.obj" ${dep_str})
|
||||
gcv_regress_util("obj_unnamed_group" "tetra-unnamed-group.obj" DEPS "gcv;gcv-obj")
|
||||
gcv_regress_util("obj" "tetra.g" ${dep_str} EXPORTER)
|
||||
distclean("${CMAKE_CURRENT_BINARY_DIR}/conv-tetra.mtl")
|
||||
distclean("${CMAKE_CURRENT_BINARY_DIR}/conv-regress-g-obj-tetra.mtl")
|
||||
|
||||
cmakefiles(
|
||||
CMakeLists.txt
|
||||
|
||||
@@ -68,6 +68,13 @@
|
||||
* ("/tc6_reg.c/sub6.s#sub"), so the lookup missed and no variant was
|
||||
* applied, leaving the phantom face. After the fix the plan is built
|
||||
* from region roots so keys match and the phantom face is eliminated.
|
||||
*
|
||||
* TC7 - NMG Boolean isolation and output modes: verifies that an interrupted
|
||||
* worker cannot commit output, then exercises BoT, NMG, region, and
|
||||
* in-place output paths.
|
||||
*
|
||||
* TC8 - implicit solid roots survive the working-database close and remain
|
||||
* valid members of the imported output hierarchy.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
@@ -78,7 +85,9 @@
|
||||
#include <string>
|
||||
|
||||
#include "bu/app.h"
|
||||
#include "bu/env.h"
|
||||
#include "bu/file.h"
|
||||
#include "bu/log.h"
|
||||
#include "bu/malloc.h"
|
||||
#include "bu/str.h"
|
||||
#include "bu/vls.h"
|
||||
@@ -142,6 +151,36 @@ write_comb2(struct rt_wdb *wdbp,
|
||||
0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
write_comb1(struct rt_wdb *wdbp, const char *comb_name, const char *member, int is_region)
|
||||
{
|
||||
struct bu_list head;
|
||||
BU_LIST_INIT(&head);
|
||||
mk_addmember(member, &head, NULL, WMOP_UNION);
|
||||
return mk_comb(wdbp, comb_name, &head, is_region, NULL, NULL, NULL,
|
||||
0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
run_facetize_command(const char *gfile, int argc, const char **argv, int verbose)
|
||||
{
|
||||
struct ged *gedp = ged_open("db", gfile, 1);
|
||||
if (!gedp) {
|
||||
bu_log("[regress_facetize] ged_open(%s) failed\n", gfile);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
int ret = ged_exec(gedp, argc, argv);
|
||||
if (verbose || ret != BRLCAD_OK) {
|
||||
const char *log = bu_vls_cstr(gedp->ged_result_str);
|
||||
if (log && log[0])
|
||||
bu_log("[facetize] %s\n", log);
|
||||
}
|
||||
|
||||
ged_close(gedp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open @a gfile with ged_open and run "facetize @a input @a output".
|
||||
* Returns BRLCAD_OK on success, BRLCAD_ERROR otherwise.
|
||||
@@ -149,23 +188,8 @@ write_comb2(struct rt_wdb *wdbp,
|
||||
static int
|
||||
run_facetize(const char *gfile, const char *input, const char *output, int verbose)
|
||||
{
|
||||
struct ged *gedp = ged_open("db", gfile, 1);
|
||||
if (!gedp) {
|
||||
bu_log("[regress_facetize] ged_open(%s) failed\n", gfile);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
const char *av[4] = {"facetize", input, output, NULL};
|
||||
int ret = ged_exec(gedp, 3, av);
|
||||
|
||||
if (verbose || ret != BRLCAD_OK) {
|
||||
const char *log = bu_vls_cstr(gedp->ged_result_str);
|
||||
if (log && log[0])
|
||||
bu_log("[facetize] %s\n", log);
|
||||
}
|
||||
|
||||
ged_close(gedp);
|
||||
return ret;
|
||||
return run_facetize_command(gfile, 3, av, verbose);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,6 +236,46 @@ bu_log("[regress_facetize] check_bot: '%s' type %d is not a BoT\n",
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
check_object_type(const char *gfile, const char *object_name, int expected_type)
|
||||
{
|
||||
struct db_i *dbip = db_open(gfile, DB_OPEN_READONLY);
|
||||
if (!dbip || db_dirbuild(dbip) < 0) {
|
||||
if (dbip)
|
||||
db_close(dbip);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
struct directory *dp = db_lookup(dbip, object_name, LOOKUP_QUIET);
|
||||
if (!dp) {
|
||||
bu_log("[regress_facetize] '%s' does not exist\n", object_name);
|
||||
db_close(dbip);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
struct rt_db_internal intern;
|
||||
RT_DB_INTERNAL_INIT(&intern);
|
||||
if (rt_db_get_internal(&intern, dp, dbip, NULL) < 0) {
|
||||
db_close(dbip);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
int ret = (intern.idb_minor_type == expected_type) ? BRLCAD_OK : BRLCAD_ERROR;
|
||||
if (ret != BRLCAD_OK)
|
||||
bu_log("[regress_facetize] '%s' type %d, expected %d\n",
|
||||
object_name, intern.idb_minor_type, expected_type);
|
||||
rt_db_free_internal(&intern);
|
||||
db_close(dbip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
count_log_hook(void *data, void *UNUSED(message))
|
||||
{
|
||||
int *count = (int *)data;
|
||||
(*count)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run rt_crofton_shoot on @a obj_name in @a gfile.
|
||||
* Stores SA (mm2) and VOL (mm3) in *sa / *vol.
|
||||
@@ -1120,6 +1184,183 @@ tc6_havoc_wind9_pattern(const char *tmpdir, int verbose)
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
tc7_nmg_modes(const char *tmpdir, int verbose)
|
||||
{
|
||||
bu_log("[regress_facetize] TC7: NMG Boolean and output modes...\n");
|
||||
|
||||
struct bu_vls gpath = BU_VLS_INIT_ZERO;
|
||||
bu_vls_printf(&gpath, "%s/tc7_nmg.g", tmpdir);
|
||||
const char *gfile = bu_vls_cstr(&gpath);
|
||||
if (bu_file_exists(gfile, NULL))
|
||||
bu_file_delete(gfile);
|
||||
|
||||
struct db_i *dbip = db_create(gfile, 5);
|
||||
if (!dbip) {
|
||||
bu_vls_free(&gpath);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
struct rt_wdb *wdbp = wdb_dbopen(dbip, RT_WDB_TYPE_DB_DEFAULT);
|
||||
point_t box_pts[8] = {
|
||||
{0.0, 0.0, 0.0}, {10.0, 0.0, 0.0},
|
||||
{10.0, 10.0, 0.0}, {0.0, 10.0, 0.0},
|
||||
{0.0, 0.0, 10.0}, {10.0, 0.0, 10.0},
|
||||
{10.0, 10.0, 10.0}, {0.0, 10.0, 10.0}
|
||||
};
|
||||
if (write_arb8(wdbp, "box.s", box_pts) < 0 ||
|
||||
write_comb1(wdbp, "box.r", "box.s", 1) < 0 ||
|
||||
write_comb1(wdbp, "box.c", "box.s", 0) < 0) {
|
||||
wdb_close(wdbp);
|
||||
bu_vls_free(&gpath);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
wdb_close(wdbp);
|
||||
|
||||
const char *bot_av[] = {"facetize", "--nmg-booleval", "box.r", "box.bot", NULL};
|
||||
const char *fault_av[] = {"facetize", "--nmg-booleval", "box.r", "fault.bot", NULL};
|
||||
const char *nmg_av[] = {"facetize", "-n", "box.r", "box.nmg", NULL};
|
||||
const char *regions_av[] = {"facetize", "-r", "--nmg-booleval", "box.r", "box.regions", NULL};
|
||||
const char *fallback_av[] = {"facetize", "-r", "--nmg-booleval", "box.c", "box-fallback.bot", NULL};
|
||||
const char *object_in_place_av[] = {"facetize", "--in-place", "--nmg-booleval", "box.c", NULL};
|
||||
const char *in_place_av[] = {"facetize", "-r", "--in-place", "--nmg-booleval", "box.r", NULL};
|
||||
|
||||
int ret = BRLCAD_OK;
|
||||
auto check_tc7 = [&ret](bool passed, const char *description) {
|
||||
if (passed)
|
||||
return;
|
||||
bu_log("[regress_facetize] TC7: FAIL - %s\n", description);
|
||||
ret = BRLCAD_ERROR;
|
||||
};
|
||||
|
||||
struct bu_vls fault_path = BU_VLS_INIT_ZERO;
|
||||
bu_vls_printf(&fault_path, "%s/tc7_nmg_worker.fault", tmpdir);
|
||||
(void)bu_file_delete(bu_vls_cstr(&fault_path));
|
||||
(void)bu_setenv("LIBGED_FACETIZE_TEST_FAULT",
|
||||
"nmg-before-ready:fault.bot", 1);
|
||||
(void)bu_setenv("LIBGED_FACETIZE_TEST_FAULT_FILE",
|
||||
bu_vls_cstr(&fault_path), 1);
|
||||
int fault_ret = run_facetize_command(gfile, 4, fault_av, verbose);
|
||||
(void)bu_setenv("LIBGED_FACETIZE_TEST_FAULT", "", 1);
|
||||
(void)bu_setenv("LIBGED_FACETIZE_TEST_FAULT_FILE", "", 1);
|
||||
check_tc7(fault_ret == BRLCAD_ERROR,
|
||||
"an interrupted NMG Boolean worker did not report failure");
|
||||
check_tc7(bu_file_exists(bu_vls_cstr(&fault_path), NULL),
|
||||
"NMG Boolean worker fault did not trigger");
|
||||
check_tc7(check_object_type(gfile, "fault.bot", ID_BOT) != BRLCAD_OK,
|
||||
"an interrupted NMG Boolean worker committed an output");
|
||||
(void)bu_file_delete(bu_vls_cstr(&fault_path));
|
||||
bu_vls_free(&fault_path);
|
||||
|
||||
int hook_calls = 0;
|
||||
bu_log_add_hook(count_log_hook, &hook_calls);
|
||||
int bot_ret = run_facetize_command(gfile, 4, bot_av, verbose);
|
||||
int hook_calls_before_probe = hook_calls;
|
||||
bu_log("facetize NMG hook restoration probe\n");
|
||||
bu_log_delete_hook(count_log_hook, &hook_calls);
|
||||
|
||||
check_tc7(bot_ret == BRLCAD_OK, "NMG Boolean BoT command failed");
|
||||
check_tc7(hook_calls == hook_calls_before_probe + 1,
|
||||
"temporary log hook was not restored");
|
||||
check_tc7(check_bot_exists(gfile, "box.bot") == BRLCAD_OK,
|
||||
"NMG Boolean BoT output is missing");
|
||||
|
||||
int nmg_ret = run_facetize_command(gfile, 4, nmg_av, verbose);
|
||||
check_tc7(nmg_ret == BRLCAD_OK, "NMG output command failed");
|
||||
check_tc7(check_object_type(gfile, "box.nmg", ID_NMG) == BRLCAD_OK,
|
||||
"NMG output has the wrong type");
|
||||
|
||||
int regions_ret = run_facetize_command(gfile, 5, regions_av, verbose);
|
||||
check_tc7(regions_ret == BRLCAD_OK, "NMG Boolean region command failed");
|
||||
check_tc7(check_object_type(gfile, "box.regions", ID_COMBINATION) == BRLCAD_OK,
|
||||
"NMG Boolean region output is missing");
|
||||
|
||||
int fallback_ret = run_facetize_command(gfile, 5, fallback_av, verbose);
|
||||
check_tc7(fallback_ret == BRLCAD_OK,
|
||||
"region mode object fallback command failed");
|
||||
check_tc7(check_bot_exists(gfile, "box-fallback.bot") == BRLCAD_OK,
|
||||
"region mode object fallback output is missing");
|
||||
|
||||
int object_in_place_ret = run_facetize_command(gfile, 4,
|
||||
object_in_place_av, verbose);
|
||||
check_tc7(object_in_place_ret == BRLCAD_OK,
|
||||
"in-place NMG Boolean object command failed");
|
||||
check_tc7(check_object_type(gfile, "box.c", ID_BOT) == BRLCAD_OK,
|
||||
"in-place NMG Boolean object has the wrong type");
|
||||
|
||||
int in_place_ret = run_facetize_command(gfile, 5, in_place_av, verbose);
|
||||
check_tc7(in_place_ret == BRLCAD_OK,
|
||||
"in-place NMG Boolean region command failed");
|
||||
check_tc7(check_object_type(gfile, "box.r", ID_COMBINATION) == BRLCAD_OK,
|
||||
"in-place region root has the wrong type");
|
||||
check_tc7(check_bot_exists(gfile, "box.r.bot") == BRLCAD_OK,
|
||||
"in-place region BoT output is missing");
|
||||
|
||||
bu_log("[regress_facetize] TC7: %s\n", ret == BRLCAD_OK ? "PASS" : "FAIL");
|
||||
bu_vls_free(&gpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* TC8: implicit root replacement persists across database reopen */
|
||||
/* ------------------------------------------------------------------ */
|
||||
static int
|
||||
tc8_implicit_root_persistence(const char *tmpdir, int verbose)
|
||||
{
|
||||
bu_log("[regress_facetize] TC8: implicit root persistence...\n");
|
||||
|
||||
struct bu_vls gpath = BU_VLS_INIT_ZERO;
|
||||
bu_vls_printf(&gpath, "%s/tc8_implicit_root.g", tmpdir);
|
||||
const char *gfile = bu_vls_cstr(&gpath);
|
||||
if (bu_file_exists(gfile, NULL))
|
||||
bu_file_delete(gfile);
|
||||
|
||||
struct db_i *dbip = db_create(gfile, 5);
|
||||
if (!dbip) {
|
||||
bu_vls_free(&gpath);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
struct rt_wdb *wdbp = wdb_dbopen(dbip, RT_WDB_TYPE_DB_DEFAULT);
|
||||
point_t region_points[8] = {
|
||||
{0.0, 0.0, 0.0}, {10.0, 0.0, 0.0},
|
||||
{10.0, 10.0, 0.0}, {0.0, 10.0, 0.0},
|
||||
{0.0, 0.0, 10.0}, {10.0, 0.0, 10.0},
|
||||
{10.0, 10.0, 10.0}, {0.0, 10.0, 10.0}
|
||||
};
|
||||
point_t loose_points[8] = {
|
||||
{20.0, 0.0, 0.0}, {30.0, 0.0, 0.0},
|
||||
{30.0, 10.0, 0.0}, {20.0, 10.0, 0.0},
|
||||
{20.0, 0.0, 10.0}, {30.0, 0.0, 10.0},
|
||||
{30.0, 10.0, 10.0}, {20.0, 10.0, 10.0}
|
||||
};
|
||||
if (!wdbp || write_arb8(wdbp, "region.s", region_points) < 0 ||
|
||||
write_arb8(wdbp, "loose.s", loose_points) < 0 ||
|
||||
write_comb1(wdbp, "box.r", "region.s", 1) < 0 ||
|
||||
write_comb2(wdbp, "assembly.c", "box.r", 'u',
|
||||
"loose.s", 'u') < 0) {
|
||||
if (wdbp)
|
||||
wdb_close(wdbp);
|
||||
bu_vls_free(&gpath);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
wdb_close(wdbp);
|
||||
|
||||
const char *facetize_args[] = {
|
||||
"facetize", "-r", "assembly.c", "assembly.regions", NULL
|
||||
};
|
||||
int ret = run_facetize_command(gfile, 4, facetize_args, verbose);
|
||||
if (ret == BRLCAD_OK &&
|
||||
(check_object_type(gfile, "assembly.regions", ID_COMBINATION) != BRLCAD_OK ||
|
||||
check_object_type(gfile, "facetize_assembly.c", ID_COMBINATION) != BRLCAD_OK ||
|
||||
check_bot_exists(gfile, "box.r.bot") != BRLCAD_OK ||
|
||||
check_bot_exists(gfile, "facetize_loose.s") != BRLCAD_OK))
|
||||
ret = BRLCAD_ERROR;
|
||||
|
||||
bu_log("[regress_facetize] TC8: %s\n",
|
||||
ret == BRLCAD_OK ? "PASS" : "FAIL");
|
||||
bu_vls_free(&gpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* main */
|
||||
/* ------------------------------------------------------------------ */
|
||||
@@ -1151,6 +1392,8 @@ return 1;
|
||||
if (tc4_havoc_reuse(tmpdir, verbose) != BRLCAD_OK) ret = 1;
|
||||
if (tc5_near_coplanar_subTOL(tmpdir, verbose) != BRLCAD_OK) ret = 1;
|
||||
if (tc6_havoc_wind9_pattern(tmpdir, verbose) != BRLCAD_OK) ret = 1;
|
||||
if (tc7_nmg_modes(tmpdir, verbose) != BRLCAD_OK) ret = 1;
|
||||
if (tc8_implicit_root_persistence(tmpdir, verbose) != BRLCAD_OK) ret = 1;
|
||||
|
||||
if (ret == 0)
|
||||
bu_log("[regress_facetize] All tests PASSED\n");
|
||||
|
||||
@@ -23,6 +23,7 @@ set(
|
||||
gqa.mass_mix.am.out
|
||||
gqa.mass_mix.aw.out
|
||||
gqa.mass_mix.u0.out
|
||||
gqa.missing_density.out
|
||||
gqa.mged
|
||||
gqa.overlaps.plot3
|
||||
gqa.sphere_adaptive.out
|
||||
|
||||
@@ -67,6 +67,11 @@ run_capture ( ) {
|
||||
return $ret
|
||||
}
|
||||
|
||||
expect_failure ( ) {
|
||||
"$@"
|
||||
test $? -ne 0
|
||||
}
|
||||
|
||||
extract_last_number ( ) {
|
||||
label="$1"
|
||||
file="$2"
|
||||
@@ -101,6 +106,19 @@ assert_close ( ) {
|
||||
fi
|
||||
}
|
||||
|
||||
assert_contains ( ) {
|
||||
expected="$1"
|
||||
file="$2"
|
||||
desc="$3"
|
||||
|
||||
if grep -F -q "$expected" "$file" ; then
|
||||
log "PASS: $desc"
|
||||
else
|
||||
log "FAIL: $desc"
|
||||
STATUS="`expr $STATUS + 1`"
|
||||
fi
|
||||
}
|
||||
|
||||
MGED="`ensearch mged`"
|
||||
if test ! -f "$MGED" ; then
|
||||
log "Unable to find mged, aborting"
|
||||
@@ -177,6 +195,10 @@ adjust mass_air.r GIFTmater 2
|
||||
g mass_air_only.g mass_air.r
|
||||
g mass_air_mix.g mass_solid.r mass_air.r
|
||||
|
||||
in missing_density.s rpp 2 3 0 1 0 1
|
||||
r missing_density.r u missing_density.s
|
||||
adjust missing_density.r GIFTmater 123
|
||||
|
||||
in sphere.s sph 0 0 0 1
|
||||
r sphere.r u sphere.s
|
||||
adjust sphere.r GIFTmater 5
|
||||
@@ -243,6 +265,7 @@ run_capture gqa.mass_mix.aw.out $GQABIN -u m,m^3,kg -g 250mm-50mm -Aw gqa.g mass
|
||||
run_capture gqa.mass_mix.am.out $GQABIN -u m,m^3,kg -g 250mm-50mm -Am gqa.g mass_air_mix.g
|
||||
run_capture gqa.mass_mix.u0.out $GQABIN -u m,m^3,kg -g 250mm-50mm -U 0 -Aw gqa.g mass_air_mix.g
|
||||
run_capture gqa.sphere_adaptive.out $GQABIN -u m,m^3,kg -q -Av -g 0.05m gqa.g sphere.r
|
||||
run_capture gqa.missing_density.out expect_failure $GQABIN -u m,m^3,kg -g 250mm-50mm -f density_table.txt -Aw gqa.g missing_density.r
|
||||
|
||||
MASS_AIR_AW="`extract_last_number 'Average total weight:' gqa.mass_air.aw.out`"
|
||||
MASS_AIR_AM="`extract_last_number 'Average total weight:' gqa.mass_air.am.out`"
|
||||
@@ -257,6 +280,7 @@ assert_close 1001 "$MASS_MIX_AW" 0.001 "mixed solid+air modeled weight with -Aw"
|
||||
assert_close "$MASS_MIX_AW" "$MASS_MIX_AM" 0.001 "-Aw and -Am agree on mixed modeled air"
|
||||
assert_close 1000 "$MASS_MIX_U0" 0.001 "-U 0 excludes modeled air from weight"
|
||||
assert_close 4.18879 "$SPHERE_VOLUME" 0.01 "adaptive sphere volume refines beyond symmetric first pass"
|
||||
assert_contains "Density 123 on region /missing_density.r is not defined in the density table." gqa.missing_density.out "undefined density produces an error"
|
||||
|
||||
|
||||
if [ $STATUS = 0 ] ; then
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
cmakefiles(
|
||||
CMakeLists.txt
|
||||
README.md
|
||||
gui_test.sh
|
||||
gui_smoke.sh
|
||||
gui_tcl_test.sh
|
||||
gui_test.tcl
|
||||
gui_test_core.tcl
|
||||
sketch_test.tcl
|
||||
)
|
||||
|
||||
# Local Variables:
|
||||
# mode: cmake
|
||||
# tab-width: 2
|
||||
# indent-tabs-mode: nil
|
||||
# End:
|
||||
# ex: shiftwidth=2 tabstop=8
|
||||
@@ -0,0 +1,39 @@
|
||||
# GUI regression support
|
||||
|
||||
The shared support has three layers:
|
||||
|
||||
1. `brlcad_add_gui_test` registers a test and delegates session setup to the
|
||||
selected backend.
|
||||
2. `GUI_TEST_CTL` is the window-control interface supplied by the backend.
|
||||
3. `gui_test.sh`, `gui_smoke.sh`, `gui_tcl_test.sh`, and `gui_test.tcl` provide
|
||||
shell and Tcl helpers for application lifecycle, artifacts, window input,
|
||||
screen comparisons, widgets, menus, and asynchronous Tcl errors.
|
||||
|
||||
Application fixtures own their semantic oracles. `sketch_test.tcl` contains
|
||||
shared sketch assertions used by Archer and MGED. The core helpers do not
|
||||
encode application menus, object models, or screen layouts.
|
||||
|
||||
## Controller contract
|
||||
|
||||
The controller takes one command followed by arguments:
|
||||
|
||||
| Command | Result |
|
||||
| --- | --- |
|
||||
| `wait-window --timeout milliseconds title` | Return an opaque window token. |
|
||||
| `geometry token` | Print `x y width height`. |
|
||||
| `activate token`, `close token` | Control the identified window. |
|
||||
| `click [--delay milliseconds] token x y button`, `mouse-move token x y`, `button button down|up` | Send pointer input. |
|
||||
| `key name`, `type text` | Send keyboard input. |
|
||||
| `wait-stable --quiet milliseconds --timeout milliseconds token` | Wait for visual quiescence. |
|
||||
| `capture-screen path` | Write a binary PPM of the composed screen. |
|
||||
| `screen-geometry` | Print `width height`. |
|
||||
|
||||
`root` denotes screen coordinates. Tk fixtures publish `winfo id` values as
|
||||
window tokens and widget-local points as coordinates. The backend resolves
|
||||
the tokens; fixtures do not interpret their representation. Capture and
|
||||
screen geometry must describe the same screen so root-coordinate cropping is
|
||||
consistent.
|
||||
|
||||
The only implemented backend is Xmin. See [its fixtures](../xmin/README.md)
|
||||
for setup and test coverage. A native backend will also need a CMake session
|
||||
provider and working display/input permissions on its runner.
|
||||
@@ -0,0 +1,88 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
: "${GUI_TEST_SHELL:?GUI_TEST_SHELL is required}"
|
||||
. "$GUI_TEST_SHELL"
|
||||
|
||||
gui_stop_app()
|
||||
{
|
||||
if [ -n "${GUI_APP_PID:-}" ] && kill -0 "$GUI_APP_PID" 2>/dev/null; then
|
||||
kill "$GUI_APP_PID" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "Usage: $0 expected-window executable [argument ...]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
: "${GUI_TEST_CTL:?GUI_TEST_CTL is required}"
|
||||
expected_window=$1
|
||||
shift
|
||||
application=$1
|
||||
shift
|
||||
|
||||
gui_require_executable "$GUI_TEST_CTL"
|
||||
gui_require_executable "$application"
|
||||
|
||||
GUI_ARTIFACT_DIR=$(mktemp -d "${TMPDIR:-/tmp}/brlcad-gui-smoke.XXXXXX")
|
||||
export GUI_ARTIFACT_DIR
|
||||
GUI_APP_LOG="$GUI_ARTIFACT_DIR/application.log"
|
||||
export GUI_APP_LOG
|
||||
trap gui_stop_app EXIT INT TERM
|
||||
|
||||
"$application" "$@" >"$GUI_APP_LOG" 2>&1 &
|
||||
GUI_APP_PID=$!
|
||||
export GUI_APP_PID
|
||||
|
||||
if ! window_id=$("$GUI_TEST_CTL" wait-window --timeout "$GUI_WAIT_TIMEOUT_MS" \
|
||||
"$expected_window"); then
|
||||
gui_fail "window did not appear: $expected_window"
|
||||
fi
|
||||
if ! kill -0 "$GUI_APP_PID" 2>/dev/null; then
|
||||
"$GUI_TEST_CTL" wait-stable --quiet "$GUI_STABLE_QUIET_MS" \
|
||||
--timeout "$GUI_STABLE_TIMEOUT_MS" "$window_id" >/dev/null 2>&1 || true
|
||||
gui_fail "application exited before its window could be tested"
|
||||
fi
|
||||
|
||||
"$GUI_TEST_CTL" activate "$window_id"
|
||||
if ! geometry=$(gui_wait_for_minimum_geometry "$window_id" \
|
||||
"$GUI_MIN_WINDOW_WIDTH" "$GUI_MIN_WINDOW_HEIGHT"); then
|
||||
gui_fail "window did not reach a usable geometry: $expected_window ($geometry)"
|
||||
fi
|
||||
|
||||
gui_capture_screen "$window_id" "$GUI_ARTIFACT_DIR/before.ppm"
|
||||
|
||||
if [ -n "${GUI_SMOKE_ACTION:-}" ]; then
|
||||
gui_require_executable "$GUI_SMOKE_ACTION"
|
||||
"$GUI_SMOKE_ACTION" "$window_id" "$GUI_ARTIFACT_DIR"
|
||||
if [ "${GUI_MIN_CHANGED_BYTES:-0}" -gt 0 ]; then
|
||||
gui_wait_for_image_difference "$GUI_ARTIFACT_DIR/before.ppm" \
|
||||
"$GUI_ARTIFACT_DIR/after.ppm" "$GUI_MIN_CHANGED_BYTES" \
|
||||
"$window_id"
|
||||
else
|
||||
gui_capture_screen "$window_id" "$GUI_ARTIFACT_DIR/after.ppm"
|
||||
fi
|
||||
fi
|
||||
|
||||
"$GUI_TEST_CTL" close "$window_id"
|
||||
wait "$GUI_APP_PID"
|
||||
GUI_APP_PID=
|
||||
|
||||
if [ "${GUI_KEEP_ARTIFACTS:-0}" -eq 1 ]; then
|
||||
echo "GUI smoke artifacts: $GUI_ARTIFACT_DIR"
|
||||
else
|
||||
"${CMAKE_COMMAND:-cmake}" -E remove_directory "$GUI_ARTIFACT_DIR"
|
||||
fi
|
||||
|
||||
echo "PASS: $expected_window launched, rendered, and closed"
|
||||
|
||||
# Local Variables:
|
||||
# tab-width: 8
|
||||
# mode: sh
|
||||
# sh-indentation: 4
|
||||
# sh-basic-offset: 4
|
||||
# indent-tabs-mode: t
|
||||
# End:
|
||||
# ex: shiftwidth=4 tabstop=8 cino=N-s
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
: "${GUI_TEST_SHELL:?GUI_TEST_SHELL is required}"
|
||||
. "$GUI_TEST_SHELL"
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "Usage: $0 test-name executable [argument ...]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
test_name=$1
|
||||
shift
|
||||
test_program=$1
|
||||
|
||||
gui_require_executable "$test_program"
|
||||
|
||||
GUI_TEST_DIR=$(mktemp -d "${TMPDIR:-/tmp}/brlcad-gui-${test_name}.XXXXXX")
|
||||
export GUI_TEST_DIR
|
||||
|
||||
gui_tcl_test_cleanup()
|
||||
{
|
||||
if [ "${GUI_KEEP_ARTIFACTS:-0}" -eq 0 ]; then
|
||||
"${CMAKE_COMMAND:-cmake}" -E remove_directory "$GUI_TEST_DIR"
|
||||
fi
|
||||
}
|
||||
trap 'exit 1' INT TERM
|
||||
|
||||
if ! "$@"; then
|
||||
echo "GUI test artifacts: $GUI_TEST_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -s "$GUI_TEST_DIR/result" ]; then
|
||||
test_result=$(sed -n '1p' "$GUI_TEST_DIR/result")
|
||||
case "$test_result" in
|
||||
PASS:*) ;;
|
||||
*)
|
||||
echo "$test_result" >&2
|
||||
echo "GUI test artifacts: $GUI_TEST_DIR" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "${GUI_KEEP_ARTIFACTS:-0}" -eq 1 ]; then
|
||||
echo "GUI test artifacts: $GUI_TEST_DIR"
|
||||
else
|
||||
gui_tcl_test_cleanup
|
||||
fi
|
||||
|
||||
# Local Variables:
|
||||
# tab-width: 8
|
||||
# mode: sh
|
||||
# sh-indentation: 4
|
||||
# sh-basic-offset: 4
|
||||
# indent-tabs-mode: t
|
||||
# End:
|
||||
# ex: shiftwidth=4 tabstop=8 cino=N-s
|
||||
@@ -0,0 +1,156 @@
|
||||
#!/bin/sh
|
||||
|
||||
GUI_WAIT_TIMEOUT_MS=${GUI_WAIT_TIMEOUT_MS:-30000}
|
||||
GUI_STABLE_QUIET_MS=${GUI_STABLE_QUIET_MS:-200}
|
||||
GUI_STABLE_TIMEOUT_MS=${GUI_STABLE_TIMEOUT_MS:-5000}
|
||||
GUI_POLL_SECONDS=${GUI_POLL_SECONDS:-0.05}
|
||||
GUI_MIN_WINDOW_WIDTH=${GUI_MIN_WINDOW_WIDTH:-200}
|
||||
GUI_MIN_WINDOW_HEIGHT=${GUI_MIN_WINDOW_HEIGHT:-150}
|
||||
|
||||
gui_fail()
|
||||
{
|
||||
echo "FAIL: $1" >&2
|
||||
if [ -n "${GUI_APP_LOG:-}" ] && [ -f "$GUI_APP_LOG" ]; then
|
||||
sed -n '1,240p' "$GUI_APP_LOG" >&2
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
gui_require_executable()
|
||||
{
|
||||
if [ ! -x "$1" ]; then
|
||||
gui_fail "required executable is unavailable: $1"
|
||||
fi
|
||||
}
|
||||
|
||||
gui_wait_for_minimum_geometry()
|
||||
{
|
||||
window=$1
|
||||
minimum_width=$2
|
||||
minimum_height=$3
|
||||
timeout_seconds=$(((GUI_WAIT_TIMEOUT_MS + 999) / 1000))
|
||||
start_time=$(date +%s)
|
||||
|
||||
while :; do
|
||||
geometry=$("$GUI_TEST_CTL" geometry "$window") || return 1
|
||||
set -- $geometry
|
||||
if [ "$#" -ge 4 ]; then
|
||||
width=$3
|
||||
height=$4
|
||||
if [ "$width" -ge "$minimum_width" ] &&
|
||||
[ "$height" -ge "$minimum_height" ]; then
|
||||
echo "$geometry"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
current_time=$(date +%s)
|
||||
if [ $((current_time - start_time)) -ge "$timeout_seconds" ]; then
|
||||
echo "$geometry"
|
||||
return 1
|
||||
fi
|
||||
sleep "$GUI_POLL_SECONDS"
|
||||
done
|
||||
}
|
||||
|
||||
gui_capture_screen()
|
||||
{
|
||||
window=$1
|
||||
output=$2
|
||||
"$GUI_TEST_CTL" wait-stable --quiet "$GUI_STABLE_QUIET_MS" \
|
||||
--timeout "$GUI_STABLE_TIMEOUT_MS" "$window" >/dev/null 2>&1 || true
|
||||
# Tk and Qt compose child windows into the root; a top-level-only capture
|
||||
# can therefore contain just the parent's cleared backing surface.
|
||||
"$GUI_TEST_CTL" capture-screen "$output" ||
|
||||
gui_fail "could not capture the GUI test screen"
|
||||
if [ "$(sed -n '1p' "$output")" != "P6" ]; then
|
||||
gui_fail "screen capture is not a binary PPM image: $output"
|
||||
fi
|
||||
nonzero_bytes=$(LC_ALL=C tr -d '\000' < "$output" | wc -c | tr -d ' ')
|
||||
if [ "$nonzero_bytes" -lt 1024 ]; then
|
||||
gui_fail "screen capture contains no meaningful rendered content"
|
||||
fi
|
||||
}
|
||||
|
||||
gui_count_changed_bytes()
|
||||
{
|
||||
first=$1
|
||||
second=$2
|
||||
minimum=$3
|
||||
# Stop once the threshold is reached. Full root captures are large, and
|
||||
# their exact total difference is immaterial to this binary assertion.
|
||||
changed_bytes=$(cmp -l "$first" "$second" | awk -v minimum="$minimum" \
|
||||
'NR >= minimum { print NR; exit }
|
||||
END { if (NR < minimum) print NR }')
|
||||
echo "$changed_bytes"
|
||||
}
|
||||
|
||||
gui_wait_for_image_difference()
|
||||
{
|
||||
first=$1
|
||||
second=$2
|
||||
minimum=$3
|
||||
window=$4
|
||||
timeout_seconds=$(((GUI_WAIT_TIMEOUT_MS + 999) / 1000))
|
||||
start_time=$(date +%s)
|
||||
|
||||
if [ ! -s "$first" ]; then
|
||||
gui_fail "cannot compare a missing or empty GUI capture: $first"
|
||||
fi
|
||||
|
||||
while :; do
|
||||
gui_capture_screen "$window" "$second"
|
||||
changed_bytes=$(gui_count_changed_bytes "$first" "$second" "$minimum")
|
||||
if [ "$changed_bytes" -ge "$minimum" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
current_time=$(date +%s)
|
||||
if [ $((current_time - start_time)) -ge "$timeout_seconds" ]; then
|
||||
gui_fail "GUI captures changed by only $changed_bytes bytes; expected at least $minimum"
|
||||
fi
|
||||
sleep "$GUI_POLL_SECONDS"
|
||||
done
|
||||
}
|
||||
|
||||
# Capture a root-coordinate region of the screen as PPM. The conversion
|
||||
# commands preserve the image comparison format used by the MGED fixture.
|
||||
gui_capture_region()
|
||||
(
|
||||
output=$1
|
||||
x=$2
|
||||
y=$3
|
||||
width=$4
|
||||
height=$5
|
||||
root_capture=${output%.ppm}-root.ppm
|
||||
root_pixels=${output%.ppm}-root.pix
|
||||
cropped_pixels=${output%.ppm}-cropped.pix
|
||||
geometry=$("$GUI_TEST_CTL" screen-geometry) || exit 1
|
||||
set -- $geometry
|
||||
screen_width=$1
|
||||
screen_height=$2
|
||||
lower_y=$((screen_height - y - height))
|
||||
upper_y=$((lower_y + height - 1))
|
||||
right_x=$((x + width - 1))
|
||||
|
||||
"$GUI_TEST_CTL" wait-stable --quiet "$GUI_STABLE_QUIET_MS" \
|
||||
--timeout "$GUI_STABLE_TIMEOUT_MS" root >/dev/null 2>&1 || true
|
||||
"$GUI_TEST_CTL" capture-screen "$root_capture" || exit 1
|
||||
"$ICV_BIN" "$root_capture" "$root_pixels" >/dev/null 2>&1 || exit 1
|
||||
"$PIXCROP_BIN" "$root_pixels" "$cropped_pixels" \
|
||||
"$screen_width" "$width" "$height" \
|
||||
"$x" "$upper_y" "$right_x" "$upper_y" \
|
||||
"$right_x" "$lower_y" "$x" "$lower_y" >/dev/null 2>&1 || exit 1
|
||||
"$ICV_BIN" -w "$width" -n "$height" \
|
||||
"$cropped_pixels" "$output" >/dev/null 2>&1 || exit 1
|
||||
rm -f "$root_capture" "$root_pixels" "$cropped_pixels"
|
||||
)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width: 8
|
||||
# mode: sh
|
||||
# sh-indentation: 4
|
||||
# sh-basic-offset: 4
|
||||
# indent-tabs-mode: t
|
||||
# End:
|
||||
# ex: shiftwidth=4 tabstop=8 cino=N-s
|
||||
@@ -1,4 +1,4 @@
|
||||
# X M I N _ G U I _ T E S T . T C L
|
||||
# G U I _ T E S T . T C L
|
||||
# BRL-CAD
|
||||
#
|
||||
# Copyright (c) 2026 United States Government as represented by
|
||||
@@ -18,14 +18,14 @@
|
||||
# information.
|
||||
#
|
||||
###
|
||||
source [file join [file dirname [info script]] xmin_test.tcl]
|
||||
source [file join [file dirname [info script]] gui_test_core.tcl]
|
||||
|
||||
namespace eval ::xmin::test {
|
||||
namespace eval ::gui::test {
|
||||
variable background_errors {}
|
||||
variable numeric_tolerance 1.0e-12
|
||||
}
|
||||
|
||||
proc ::xmin::test::record_background_error {message} {
|
||||
proc ::gui::test::record_background_error {message} {
|
||||
variable background_errors
|
||||
set error_info ""
|
||||
set error_code ""
|
||||
@@ -38,15 +38,15 @@ proc ::xmin::test::record_background_error {message} {
|
||||
lappend background_errors [list $message $error_info $error_code]
|
||||
}
|
||||
|
||||
proc ::xmin::test::capture_background_errors {} {
|
||||
proc ::gui::test::capture_background_errors {} {
|
||||
variable background_errors
|
||||
set background_errors {}
|
||||
proc ::bgerror {message} {
|
||||
::xmin::test::record_background_error $message
|
||||
::gui::test::record_background_error $message
|
||||
}
|
||||
}
|
||||
|
||||
proc ::xmin::test::require_no_background_errors {} {
|
||||
proc ::gui::test::require_no_background_errors {} {
|
||||
variable background_errors
|
||||
if {[llength $background_errors] == 0} {
|
||||
return
|
||||
@@ -66,7 +66,7 @@ proc ::xmin::test::require_no_background_errors {} {
|
||||
error "background Tcl error(s):\n[join $report \n]"
|
||||
}
|
||||
|
||||
proc ::xmin::test::check_background_errors {status message} {
|
||||
proc ::gui::test::check_background_errors {status message} {
|
||||
if {$status == 0 &&
|
||||
[catch {require_no_background_errors} background_error]} {
|
||||
return [list 1 "FAIL: $background_error"]
|
||||
@@ -74,13 +74,13 @@ proc ::xmin::test::check_background_errors {status message} {
|
||||
return [list $status $message]
|
||||
}
|
||||
|
||||
proc ::xmin::test::require {condition message} {
|
||||
proc ::gui::test::require {condition message} {
|
||||
if {![uplevel 1 [list expr $condition]]} {
|
||||
error $message
|
||||
}
|
||||
}
|
||||
|
||||
proc ::xmin::test::equivalent_values {first second} {
|
||||
proc ::gui::test::equivalent_values {first second} {
|
||||
variable numeric_tolerance
|
||||
if {$first eq $second} {
|
||||
return 1
|
||||
@@ -103,7 +103,7 @@ proc ::xmin::test::equivalent_values {first second} {
|
||||
return 1
|
||||
}
|
||||
|
||||
proc ::xmin::test::widget_inventory {root} {
|
||||
proc ::gui::test::widget_inventory {root} {
|
||||
set counts {}
|
||||
foreach widget [linsert [descendants $root] 0 $root] {
|
||||
set class [winfo class $widget]
|
||||
@@ -118,7 +118,7 @@ proc ::xmin::test::widget_inventory {root} {
|
||||
return [join [lsort -dictionary $inventory] "\n"]
|
||||
}
|
||||
|
||||
proc ::xmin::test::menu_inventory_walk {menu path inventory_name visited_name} {
|
||||
proc ::gui::test::menu_inventory_walk {menu path inventory_name visited_name} {
|
||||
upvar 1 $inventory_name inventory $visited_name visited
|
||||
if {[dict exists $visited $menu]} {
|
||||
return
|
||||
@@ -147,7 +147,7 @@ proc ::xmin::test::menu_inventory_walk {menu path inventory_name visited_name} {
|
||||
}
|
||||
}
|
||||
|
||||
proc ::xmin::test::menu_roots {root} {
|
||||
proc ::gui::test::menu_roots {root} {
|
||||
set roots {}
|
||||
if {![catch {set menu [$root cget -menu]}] &&
|
||||
$menu ne "" && [winfo exists $menu]} {
|
||||
@@ -177,7 +177,7 @@ proc ::xmin::test::menu_roots {root} {
|
||||
return $roots
|
||||
}
|
||||
|
||||
proc ::xmin::test::menu_inventory {root} {
|
||||
proc ::gui::test::menu_inventory {root} {
|
||||
set inventory {}
|
||||
set visited {}
|
||||
foreach menu_root [menu_roots $root] {
|
||||
@@ -191,7 +191,7 @@ proc ::xmin::test::menu_inventory {root} {
|
||||
return [join [lsort -dictionary -unique $inventory] "\n"]
|
||||
}
|
||||
|
||||
proc ::xmin::test::find_menu_entry {root labels} {
|
||||
proc ::gui::test::find_menu_entry {root labels} {
|
||||
set menu ""
|
||||
set remaining [lrange $labels 1 end]
|
||||
foreach menu_root [menu_roots $root] {
|
||||
@@ -237,7 +237,7 @@ proc ::xmin::test::find_menu_entry {root labels} {
|
||||
return $found
|
||||
}
|
||||
|
||||
proc ::xmin::test::invoke_menu_entry {root labels} {
|
||||
proc ::gui::test::invoke_menu_entry {root labels} {
|
||||
set entry [find_menu_entry $root $labels]
|
||||
if {$entry eq ""} {
|
||||
error "menu entry not found: [join $labels { > }]"
|
||||
@@ -249,75 +249,6 @@ proc ::xmin::test::invoke_menu_entry {root labels} {
|
||||
$menu invoke $index
|
||||
}
|
||||
|
||||
proc ::xmin::test::sketch_editor_stub {command args} {
|
||||
switch -- $command {
|
||||
get_scale {
|
||||
return 1.0
|
||||
}
|
||||
get_vlist {
|
||||
return {{0 0} {10 0} {5 5}}
|
||||
}
|
||||
set_radius {
|
||||
return
|
||||
}
|
||||
default {
|
||||
error "unexpected sketch editor command: $command"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc ::xmin::test::require_unit_vector {vector description} {
|
||||
lassign $vector x y
|
||||
set magnitude [expr {sqrt($x * $x + $y * $y)}]
|
||||
require {abs($magnitude - 1.0) < 1.0e-9} "$description is not a unit vector: $vector"
|
||||
}
|
||||
|
||||
proc ::xmin::test::exercise_sketch_segments {
|
||||
arc_class bezier_class application object_namespace
|
||||
} {
|
||||
set canvas .xmin_sketch_segments
|
||||
catch {destroy $canvas}
|
||||
canvas $canvas
|
||||
|
||||
set editor ::xmin::test::sketch_editor_stub
|
||||
set arc ${object_namespace}::arc_probe
|
||||
$arc_class $arc $editor $canvas {S 0 E 1 R 10 L 0 O 0}
|
||||
set start_tangent [$arc get_tangent_at_vertex 0]
|
||||
set end_tangent [$arc get_tangent_at_vertex 1]
|
||||
require_unit_vector $start_tangent "$application sketch arc start tangent"
|
||||
require_unit_vector $end_tangent "$application sketch arc end tangent"
|
||||
require {[$arc get_tangent_at_vertex 2] eq "0 0"} "$application sketch arc returned a tangent for an unrelated vertex"
|
||||
$arc draw {}
|
||||
require {[llength [$canvas find all]] == 1} "$application sketch arc did not draw on its canvas"
|
||||
$arc reverse_orientation
|
||||
set reversed_tangent [$arc get_tangent_at_vertex 0]
|
||||
lassign $start_tangent sx sy
|
||||
lassign $reversed_tangent rx ry
|
||||
require {
|
||||
abs($sx + $rx) < 1.0e-9 && abs($sy + $ry) < 1.0e-9
|
||||
} "$application sketch arc orientation did not reverse its tangent"
|
||||
::itcl::delete object $arc
|
||||
|
||||
set circle ${object_namespace}::circle_probe
|
||||
$arc_class $circle $editor $canvas {S 0 E 1 R -1 L 0 O 0}
|
||||
require_unit_vector [$circle get_tangent_at_vertex 0] "$application full-circle tangent"
|
||||
require {[$circle get_tangent_at_vertex 1] eq "0 0"} "$application full circle reported a tangent at its center"
|
||||
::itcl::delete object $circle
|
||||
|
||||
set bezier ${object_namespace}::bezier_probe
|
||||
set item_count [llength [$canvas find all]]
|
||||
$bezier_class $bezier $editor $canvas {D 2 P {0 2 1}}
|
||||
$bezier draw {}
|
||||
require {
|
||||
[llength [$canvas find all]] == $item_count + 1
|
||||
} "$application sketch Bezier did not draw on its canvas"
|
||||
require {
|
||||
[string match {*bezier D 2 P*} [$bezier serialize 1.0]]
|
||||
} "$application sketch Bezier did not serialize its control points"
|
||||
::itcl::delete object $bezier
|
||||
destroy $canvas
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# mode: Tcl
|
||||
# tab-width: 8
|
||||
@@ -1,4 +1,4 @@
|
||||
# X M I N _ T E S T . T C L
|
||||
# G U I _ T E S T _ C O R E . T C L
|
||||
# BRL-CAD
|
||||
#
|
||||
# Copyright (c) 2026 United States Government as represented by
|
||||
@@ -18,15 +18,15 @@
|
||||
# information.
|
||||
#
|
||||
###
|
||||
namespace eval ::xmin::test {
|
||||
namespace eval ::gui::test {
|
||||
variable directory
|
||||
if {![info exists ::env(XMIN_TEST_DIR)]} {
|
||||
error "XMIN_TEST_DIR is required"
|
||||
if {![info exists ::env(GUI_TEST_DIR)]} {
|
||||
error "GUI_TEST_DIR is required"
|
||||
}
|
||||
set directory $::env(XMIN_TEST_DIR)
|
||||
set directory $::env(GUI_TEST_DIR)
|
||||
}
|
||||
|
||||
proc ::xmin::test::write {name contents} {
|
||||
proc ::gui::test::write {name contents} {
|
||||
variable directory
|
||||
set destination [file join $directory $name]
|
||||
set temporary ${destination}.tmp
|
||||
@@ -36,14 +36,14 @@ proc ::xmin::test::write {name contents} {
|
||||
file rename -force $temporary $destination
|
||||
}
|
||||
|
||||
proc ::xmin::test::publish_target {name widget} {
|
||||
proc ::gui::test::publish_target {name widget} {
|
||||
write ${name}_window [winfo id $widget]
|
||||
write $name [list \
|
||||
[expr {[winfo width $widget] / 2}] \
|
||||
[expr {[winfo height $widget] / 2}]]
|
||||
}
|
||||
|
||||
proc ::xmin::test::descendants {widget} {
|
||||
proc ::gui::test::descendants {widget} {
|
||||
set descendants {}
|
||||
foreach child [winfo children $widget] {
|
||||
lappend descendants $child
|
||||
@@ -52,7 +52,7 @@ proc ::xmin::test::descendants {widget} {
|
||||
return $descendants
|
||||
}
|
||||
|
||||
proc ::xmin::test::find_widget {root class text} {
|
||||
proc ::gui::test::find_widget {root class text} {
|
||||
foreach widget [descendants $root] {
|
||||
if {[winfo class $widget] ne $class ||
|
||||
[catch {set widget_text [$widget cget -text]}] ||
|
||||
@@ -0,0 +1,96 @@
|
||||
# S K E T C H _ T E S T . T C L
|
||||
# BRL-CAD
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
#
|
||||
###
|
||||
# Shared sketch segment checks used by Archer and MGED.
|
||||
|
||||
proc ::gui::test::sketch_editor_stub {command args} {
|
||||
switch -- $command {
|
||||
get_scale {
|
||||
return 1.0
|
||||
}
|
||||
get_vlist {
|
||||
return {{0 0} {10 0} {5 5}}
|
||||
}
|
||||
set_radius {
|
||||
return
|
||||
}
|
||||
default {
|
||||
error "unexpected sketch editor command: $command"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc ::gui::test::require_unit_vector {vector description} {
|
||||
lassign $vector x y
|
||||
set magnitude [expr {sqrt($x * $x + $y * $y)}]
|
||||
require {abs($magnitude - 1.0) < 1.0e-9} "$description is not a unit vector: $vector"
|
||||
}
|
||||
|
||||
proc ::gui::test::exercise_sketch_segments {
|
||||
arc_class bezier_class application object_namespace
|
||||
} {
|
||||
set canvas .gui_sketch_segments
|
||||
catch {destroy $canvas}
|
||||
canvas $canvas
|
||||
|
||||
set editor ::gui::test::sketch_editor_stub
|
||||
set arc ${object_namespace}::arc_probe
|
||||
$arc_class $arc $editor $canvas {S 0 E 1 R 10 L 0 O 0}
|
||||
set start_tangent [$arc get_tangent_at_vertex 0]
|
||||
set end_tangent [$arc get_tangent_at_vertex 1]
|
||||
require_unit_vector $start_tangent "$application sketch arc start tangent"
|
||||
require_unit_vector $end_tangent "$application sketch arc end tangent"
|
||||
require {[$arc get_tangent_at_vertex 2] eq "0 0"} "$application sketch arc returned a tangent for an unrelated vertex"
|
||||
$arc draw {}
|
||||
require {[llength [$canvas find all]] == 1} "$application sketch arc did not draw on its canvas"
|
||||
$arc reverse_orientation
|
||||
set reversed_tangent [$arc get_tangent_at_vertex 0]
|
||||
lassign $start_tangent sx sy
|
||||
lassign $reversed_tangent rx ry
|
||||
require {
|
||||
abs($sx + $rx) < 1.0e-9 && abs($sy + $ry) < 1.0e-9
|
||||
} "$application sketch arc orientation did not reverse its tangent"
|
||||
::itcl::delete object $arc
|
||||
|
||||
set circle ${object_namespace}::circle_probe
|
||||
$arc_class $circle $editor $canvas {S 0 E 1 R -1 L 0 O 0}
|
||||
require_unit_vector [$circle get_tangent_at_vertex 0] "$application full-circle tangent"
|
||||
require {[$circle get_tangent_at_vertex 1] eq "0 0"} "$application full circle reported a tangent at its center"
|
||||
::itcl::delete object $circle
|
||||
|
||||
set bezier ${object_namespace}::bezier_probe
|
||||
set item_count [llength [$canvas find all]]
|
||||
$bezier_class $bezier $editor $canvas {D 2 P {0 2 1}}
|
||||
$bezier draw {}
|
||||
require {
|
||||
[llength [$canvas find all]] == $item_count + 1
|
||||
} "$application sketch Bezier did not draw on its canvas"
|
||||
require {
|
||||
[string match {*bezier D 2 P*} [$bezier serialize 1.0]]
|
||||
} "$application sketch Bezier did not serialize its control points"
|
||||
::itcl::delete object $bezier
|
||||
destroy $canvas
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# mode: Tcl
|
||||
# tab-width: 8
|
||||
# indent-tabs-mode: t
|
||||
# End:
|
||||
@@ -68,6 +68,7 @@ set(
|
||||
sca_view.mged
|
||||
search_exec.mged
|
||||
sed.mged
|
||||
sed_reset.mged
|
||||
set_perspective.mged
|
||||
setview.mged
|
||||
size.mged
|
||||
@@ -100,6 +101,7 @@ if(TARGET mged)
|
||||
continue()
|
||||
endif(TNAME STREQUAL "")
|
||||
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${testfile}")
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/${testfile}" TEST_CONTENTS)
|
||||
if(TNAME STREQUAL "search_exec")
|
||||
string(CONFIGURE "${TEST_CONTENTS}" TEST_CONTENTS @ONLY)
|
||||
@@ -126,6 +128,12 @@ if(TARGET mged)
|
||||
elseif(TNAME STREQUAL "arb")
|
||||
set(TEST_EXPECT "'arb' testing completed")
|
||||
set(TEST_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/regress_${testfile}")
|
||||
elseif(TNAME MATCHES "^(extrude|facedef|mirface|permute)$")
|
||||
set(TEST_EXPECT "'${TNAME}' testing completed")
|
||||
set(TEST_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/regress_${testfile}")
|
||||
elseif(TNAME STREQUAL "edgedir")
|
||||
set(TEST_EXPECT "'edarb edgedir' testing completed")
|
||||
set(TEST_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/regress_${testfile}")
|
||||
elseif(TNAME STREQUAL "killtree")
|
||||
set(TEST_EXPECT "KILL Solid: killtree_dup.s")
|
||||
set(TEST_REJECT "db_lookup(killtree_dup.s) failed")
|
||||
@@ -138,6 +146,10 @@ if(TARGET mged)
|
||||
elseif(TNAME STREQUAL "prim_edit")
|
||||
set(TEST_EXPECT "Primitive parameter editing testing completed")
|
||||
set(TEST_REJECT "FAIL:")
|
||||
elseif(TNAME STREQUAL "sed_reset")
|
||||
set(TEST_EXPECT "PASS: 'sed_reset' testing completed")
|
||||
set(TEST_REJECT "FAIL:")
|
||||
set(TEST_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/regress_${testfile}")
|
||||
elseif(TNAME STREQUAL "overlap_plotting")
|
||||
set(TEST_DB "${CMAKE_SOURCE_DIR}/src/libged/tests/ged_tests.g")
|
||||
set(TEST_EXPECT "PASS overlap plotting")
|
||||
@@ -187,6 +199,7 @@ distclean(${mged_outfiles})
|
||||
|
||||
cmakefiles(
|
||||
CMakeLists.txt
|
||||
csg_edit.mged
|
||||
mged.tcl
|
||||
regression_resources.tcl
|
||||
search_exec_procs.tcl
|
||||
|
||||
@@ -119,4 +119,35 @@ if {![catch {get $invalid_inner}]} {
|
||||
}
|
||||
|
||||
|
||||
# ARBN uses one independent thickness per plane. Exercise unequal offsets so
|
||||
# the test also verifies the plane ordering and inward normal convention.
|
||||
set arbn_outer inside_arbn_outer.s
|
||||
set arbn_inner inside_arbn_inner.s
|
||||
set arbn_thicknesses {1 2 3 4 1.5 0.5}
|
||||
in $arbn_outer arbn 6 \
|
||||
1 0 0 10 -1 0 0 0 \
|
||||
0 1 0 10 0 -1 0 0 \
|
||||
0 0 1 10 0 0 -1 0
|
||||
if {[catch {inside $arbn_outer $arbn_inner {*}$arbn_thicknesses} result]} {
|
||||
error "inside failed for ARBN: $result"
|
||||
}
|
||||
set arbn_definition [get $arbn_inner]
|
||||
set expected_offsets {9 -2 7 -4 8.5 -0.5}
|
||||
for {set plane 0} {$plane < 6} {incr plane} {
|
||||
set equation [lindex $arbn_definition [expr {4 + 2 * $plane}]]
|
||||
set actual_offset [lindex $equation 3]
|
||||
if {abs($actual_offset - [lindex $expected_offsets $plane]) > $plane_tolerance} {
|
||||
error "ARBN inside plane $plane has offset $actual_offset: $arbn_definition"
|
||||
}
|
||||
}
|
||||
facetize -n inside_arbn_inner_nmg.s $arbn_inner
|
||||
|
||||
set invalid_arbn_inner inside_arbn_invalid.s
|
||||
if {![catch {inside $arbn_outer $invalid_arbn_inner {*}[lrepeat 6 6]}]} {
|
||||
error "ARBN inside accepted thicknesses that collapse the solid"
|
||||
}
|
||||
if {![catch {get $invalid_arbn_inner}]} {
|
||||
error "ARBN inside wrote an invalid collapsed solid"
|
||||
}
|
||||
|
||||
puts "*** 'arb' testing completed ***"
|
||||
|
||||
@@ -962,8 +962,140 @@ foreach test [list \
|
||||
csg_matrix_mouse_check {*}$test
|
||||
}
|
||||
|
||||
puts "--- Repeated graphical object transforms ---"
|
||||
proc csg_matrix_repeated_mouse_check {} {
|
||||
global orig_gui transform csg_mouse_dm_pixels csg_mouse_view_size
|
||||
global csg_drag_scale
|
||||
set prim csg_matrix_repeat.s
|
||||
set inner csg_matrix_repeat_inner.c
|
||||
set outer csg_matrix_repeat_outer.c
|
||||
set saved_orig_gui $orig_gui
|
||||
set expected [csg_edit_identity_matrix]
|
||||
set failed [catch {
|
||||
in $prim sph 0 0 0 10
|
||||
comb $inner u $prim
|
||||
comb $outer u $inner
|
||||
set orig_gui 0
|
||||
for {set step 0} {$step < 16} {incr step} {
|
||||
e $outer
|
||||
center 0 0 0
|
||||
size $csg_mouse_view_size
|
||||
setview 0 0 0
|
||||
dm size $csg_mouse_dm_pixels $csg_mouse_dm_pixels
|
||||
_mged_press oill
|
||||
_mged_ill -e -i 1 /$outer/$inner/$prim
|
||||
_mged_matpick 2
|
||||
if {[status state] ne "OBJ EDIT" || $transform ne "e"} {
|
||||
error "step $step did not enter object editing"
|
||||
}
|
||||
set view_before [csg_edit_view_state]
|
||||
if {$step % 2 == 0} {
|
||||
press Rotate
|
||||
dm con r z 100 100
|
||||
set operation [csg_matrix_axis_rotation z 10]
|
||||
set motion {dm motion 140 100}
|
||||
} else {
|
||||
press Scale
|
||||
dm am s 100 100
|
||||
set operation [csg_matrix_scale all $csg_drag_scale]
|
||||
set motion {dm motion 164 100}
|
||||
}
|
||||
set motion_code [catch {uplevel #0 $motion} motion_result]
|
||||
if {$motion_code != 0 && $motion_code != 2} {
|
||||
error "step $step mouse motion failed: $motion_result"
|
||||
}
|
||||
dm idle
|
||||
press accept
|
||||
set expected [csg_matrix_multiply $operation $expected]
|
||||
csg_edit_comb_leaf_matrix_at $inner $prim $expected
|
||||
csg_edit_view_state_at $view_before
|
||||
d $outer
|
||||
}
|
||||
} failure]
|
||||
set orig_gui $saved_orig_gui
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
foreach object [list $outer $inner $prim] {
|
||||
catch {kill $object}
|
||||
}
|
||||
if {$failed} {
|
||||
puts " FAIL: repeated object mouse rotations/scales ($failure)"
|
||||
} else {
|
||||
puts " PASS: repeated object mouse rotations/scales"
|
||||
}
|
||||
}
|
||||
csg_matrix_repeated_mouse_check
|
||||
|
||||
puts "--- All ARB point, edge, and face states ---"
|
||||
|
||||
proc csg_edit_sed_point {attribute} {
|
||||
set serialized [get_sed]
|
||||
set index [lsearch -exact $serialized $attribute]
|
||||
if {$index < 0 || $index + 1 >= [llength $serialized]} {
|
||||
error "get_sed has no $attribute: $serialized"
|
||||
}
|
||||
return [lindex $serialized [expr {$index + 1}]]
|
||||
}
|
||||
|
||||
proc csg_arb_repeated_mouse_check {} {
|
||||
global orig_gui csg_bv_coord_half_range csg_mouse_dm_pixels
|
||||
global csg_mouse_view_size
|
||||
set source csg_lifecycle_arb5.s
|
||||
set prim csg_arb_repeat.s
|
||||
set saved_orig_gui $orig_gui
|
||||
set expected {}
|
||||
set failed [catch {
|
||||
cp $source $prim
|
||||
e $prim
|
||||
center 0 0 0
|
||||
size $csg_mouse_view_size
|
||||
setview 0 0 0
|
||||
dm size $csg_mouse_dm_pixels $csg_mouse_dm_pixels
|
||||
set orig_gui 0
|
||||
sed $prim
|
||||
press {Move Edges}
|
||||
press {Move Point 5}
|
||||
set original_z [lindex [db get $source V5] 2]
|
||||
for {set step 0} {$step < 64} {incr step} {
|
||||
if {$step > 0 && $step % 8 == 0} {
|
||||
press sedit
|
||||
press {Move Edges}
|
||||
press {Move Point 5}
|
||||
}
|
||||
set mouse_x [expr {150 + 2 * ($step % 5)}]
|
||||
set mouse_y [expr {150 + 2 * (($step * 3) % 5)}]
|
||||
M 1 $mouse_x $mouse_y
|
||||
set expected [list \
|
||||
[expr {$mouse_x / $csg_bv_coord_half_range * $csg_mouse_view_size / 2.0}] \
|
||||
[expr {$mouse_y / $csg_bv_coord_half_range * $csg_mouse_view_size / 2.0}] \
|
||||
$original_z]
|
||||
set actual [csg_edit_sed_point V5]
|
||||
if {[csg_edit_point_distance $actual $expected] > 0.000001} {
|
||||
error "step $step expected V5 $expected, got $actual"
|
||||
}
|
||||
}
|
||||
press accept
|
||||
d $prim
|
||||
if {[csg_edit_point_distance [db get $prim V5] $expected] > 0.000001} {
|
||||
error "accepted V5 differs from the final mouse target"
|
||||
}
|
||||
foreach vertex {V1 V2 V3 V4} {
|
||||
csg_edit_point_matches_source $source $vertex $prim
|
||||
}
|
||||
arb_standard_storage_check arb5 $prim
|
||||
} failure]
|
||||
set orig_gui $saved_orig_gui
|
||||
catch {press reject}
|
||||
catch {d $prim}
|
||||
catch {kill $prim}
|
||||
if {$failed} {
|
||||
puts " FAIL: repeated ARB5 mouse movement ($failure)"
|
||||
} else {
|
||||
puts " PASS: repeated ARB5 mouse movement"
|
||||
}
|
||||
}
|
||||
csg_arb_repeated_mouse_check
|
||||
|
||||
# Every ARB menu entry is checked independently. The variants do not share
|
||||
# menu indices, so sampling one edge or face would miss precisely the class of
|
||||
# integration failure this test is intended to catch. Move each selection a
|
||||
@@ -1322,6 +1454,280 @@ csg_edit_sequence_check csg_lifecycle_dsp.s "Toggle Smooth" {
|
||||
{press {Toggle Smooth}}
|
||||
} [list csg_edit_scalar_at sm 1]
|
||||
|
||||
puts "--- Specialized mouse editing and menu inventory ---"
|
||||
proc csg_edit_prepare_mouse_view {} {
|
||||
global csg_dispatch_view_size
|
||||
center 0 0 0
|
||||
size $csg_dispatch_view_size
|
||||
setview 0 0 0
|
||||
}
|
||||
array set csg_mouse_covered {}
|
||||
proc csg_mouse_case {source menu_items label commands validator} {
|
||||
global csg_mouse_covered
|
||||
csg_edit_sequence_check $source $label $commands $validator
|
||||
set type [lindex [db get $source] 0]
|
||||
if {![info exists csg_mouse_covered($type)]} {
|
||||
set csg_mouse_covered($type) {}
|
||||
}
|
||||
foreach item $menu_items {
|
||||
if {[lsearch -exact $csg_mouse_covered($type) $item] < 0} {
|
||||
lappend csg_mouse_covered($type) $item
|
||||
}
|
||||
}
|
||||
}
|
||||
proc csg_edit_menu_inventory_check {source ignored} {
|
||||
global csg_mouse_covered
|
||||
if {[catch {
|
||||
Z
|
||||
e $source
|
||||
sed $source
|
||||
set actual [mmenu_get 0]
|
||||
set type [lindex [db get $source] 0]
|
||||
set covered {}
|
||||
if {[info exists csg_mouse_covered($type)]} {
|
||||
set covered $csg_mouse_covered($type)
|
||||
}
|
||||
foreach item $actual {
|
||||
set tested [expr {[lsearch -exact $covered $item] >= 0}]
|
||||
set exempt [expr {[lsearch -exact $ignored $item] >= 0}]
|
||||
if {$tested == $exempt} {
|
||||
error "menu entry '$item' needs exactly one mouse-test or exclusion"
|
||||
}
|
||||
}
|
||||
foreach item [concat $covered $ignored] {
|
||||
if {[lsearch -exact $actual $item] < 0} {
|
||||
error "recorded menu entry '$item' is absent from $actual"
|
||||
}
|
||||
}
|
||||
press reject
|
||||
d $source
|
||||
} failure]} {
|
||||
puts " FAIL: menu inventory $source ($failure)"
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
} else {
|
||||
puts " PASS: menu inventory $source"
|
||||
}
|
||||
}
|
||||
|
||||
csg_edit_prepare_mouse_view
|
||||
set csg_special_mouse_target [list \
|
||||
[expr {512.0 / $csg_bv_coord_half_range * $csg_dispatch_view_size / 2.0}] \
|
||||
[expr {512.0 / $csg_bv_coord_half_range * $csg_dispatch_view_size / 2.0}] 0]
|
||||
set csg_special_mouse_scale [expr {1.0 + 2047.0 / ($csg_bv_coord_half_range * 4.0)}]
|
||||
set csg_special_mouse_shrink [expr {
|
||||
1.0 / (1.0 + 1024.0 / ($csg_bv_coord_half_range * 4.0))}]
|
||||
csg_mouse_case csg_lifecycle_pipe.s {{Move Point}} "mouse select and move point" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Select Point}}
|
||||
{p 0 0 0}
|
||||
{press {Move Point}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V0 $csg_special_mouse_target]
|
||||
in csg_mouse_pipe_topology.s pipe 4 \
|
||||
0 0 0 1 2 3 \
|
||||
0 0 30 1 2 3 \
|
||||
30 40 80 1 2 3 \
|
||||
80 80 100 1 2 3
|
||||
csg_mouse_case csg_mouse_pipe_topology.s {{Select Point} {Move Point}} "mouse select point" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Select Point}}
|
||||
{M 1 0 0}
|
||||
{press {Move Point}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V0 $csg_special_mouse_target]
|
||||
csg_mouse_case csg_mouse_pipe_topology.s {{Append Point}} "mouse append point" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Append Point}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V4 {5 5 0}]
|
||||
csg_mouse_case csg_mouse_pipe_topology.s {{Prepend Point}} "mouse prepend point" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Prepend Point}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V0 {5 5 0}]
|
||||
csg_mouse_case csg_mouse_pipe_topology.s {{Split Segment}} "mouse split segment" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Select Point}}
|
||||
{p 0 0 0}
|
||||
{press {Split Segment}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V1 {5 5 0}]
|
||||
foreach {item attribute initial} {
|
||||
{Set Point OD} O0 5
|
||||
{Set Point ID} I0 3
|
||||
{Set Point Bend} R0 6
|
||||
} {
|
||||
csg_mouse_case csg_lifecycle_pipe.s [list $item] "mouse $item" [list \
|
||||
{csg_edit_prepare_mouse_view} \
|
||||
{press {Select Point}} {p 0 0 0} [list press $item] \
|
||||
{M 1 0 -1024}] \
|
||||
[list csg_edit_scalar_at $attribute [expr {$initial * $csg_special_mouse_shrink}]]
|
||||
}
|
||||
foreach {item attributes initial} {
|
||||
{Set Pipe OD} {O0 O1 O2 O3} {5 5 6 6}
|
||||
{Set Pipe ID} {I0 I1 I2 I3} {3 3 2 0}
|
||||
{Set Pipe Bend} {R0 R1 R2 R3} {6 7 10 8}
|
||||
} {
|
||||
set expected {}
|
||||
foreach value $initial {
|
||||
lappend expected [expr {$value * $csg_special_mouse_shrink}]
|
||||
}
|
||||
csg_mouse_case csg_lifecycle_pipe.s [list $item] "mouse $item" [list \
|
||||
{csg_edit_prepare_mouse_view} \
|
||||
[list press $item] {M 1 0 -1024}] \
|
||||
[list csg_edit_scalar_values_at $attributes $expected]
|
||||
}
|
||||
proc csg_edit_bot_vertices_moved {source moved delta prim} {
|
||||
set vertices [db get $source V]
|
||||
for {set index 0} {$index < [llength $vertices]} {incr index} {
|
||||
set expected [lindex $vertices $index]
|
||||
if {[lsearch -exact $moved $index] >= 0} {
|
||||
set translated {}
|
||||
foreach value $expected shift $delta {
|
||||
lappend translated [expr {$value + $shift}]
|
||||
}
|
||||
set expected $translated
|
||||
}
|
||||
csg_edit_list_value_at V $index $expected $prim
|
||||
}
|
||||
}
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Move Vertex}} "mouse move vertex" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Vertex}}
|
||||
{p 0}
|
||||
{press {Move Vertex}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0} \
|
||||
$csg_special_mouse_target]
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Pick Vertex} {Move Vertex}} "mouse pick and move vertex" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Vertex}}
|
||||
{M 1 0 0}
|
||||
{press {Move Vertex}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0} \
|
||||
$csg_special_mouse_target]
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Move Edge}} "mouse move edge" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Edge}}
|
||||
{p 0 1}
|
||||
{press {Move Edge}}
|
||||
{M 1 1024 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0 1} {10 5 0}]
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Pick Edge} {Move Edge}} "mouse pick and move edge" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Edge}}
|
||||
{M 1 512 512}
|
||||
{press {Move Edge}}
|
||||
{M 1 1024 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0 1} {10 5 0}]
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Move Triangle}} "mouse move triangle" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Triangle}}
|
||||
{p 0 1 2}
|
||||
{press {Move Triangle}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0 1 2} \
|
||||
$csg_special_mouse_target]
|
||||
csg_mouse_case csg_lifecycle_ebm.s {{Extrude Depth}} "mouse extrusion depth" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Extrude Depth}}
|
||||
{M 1 0 2047}
|
||||
} [list csg_edit_scalar_at H [expr {4.0 * $csg_special_mouse_scale}]]
|
||||
csg_mouse_case csg_lifecycle_vol.s {{Threshold (low)}} "mouse low threshold" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Threshold (low)}}
|
||||
{p 10}
|
||||
{M 1 0 2047}
|
||||
} [list csg_edit_scalar_at lo [expr {int(10.0 * $csg_special_mouse_scale)}]]
|
||||
csg_mouse_case csg_lifecycle_vol.s {{Voxel Size (X Y Z)}} "mouse voxel size" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Voxel Size (X Y Z)}}
|
||||
{M 1 0 2047}
|
||||
} [list csg_edit_point_at size [list \
|
||||
$csg_special_mouse_scale $csg_special_mouse_scale $csg_special_mouse_scale]]
|
||||
csg_mouse_case csg_lifecycle_vol.s {{Threshold (hi)}} "mouse high threshold" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Threshold (hi)}}
|
||||
{M 1 0 -1024}
|
||||
} [list csg_edit_scalar_at hi [expr {int(255.0 * $csg_special_mouse_shrink)}]]
|
||||
csg_mouse_case csg_lifecycle_dsp.s {{Set X}} "mouse X scale" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Set X}}
|
||||
{M 1 0 2047}
|
||||
} [list csg_edit_matrix_component_at stom 0 $csg_special_mouse_scale]
|
||||
foreach {item index} {{Set Y} 5 {Set ALT} 10} {
|
||||
csg_mouse_case csg_lifecycle_dsp.s [list $item] "mouse $item" [list \
|
||||
{csg_edit_prepare_mouse_view} \
|
||||
[list press $item] {M 1 0 2047}] \
|
||||
[list csg_edit_matrix_component_at stom $index $csg_special_mouse_scale]
|
||||
}
|
||||
foreach type {arbn brep} {
|
||||
set source csg_lifecycle_${type}.s
|
||||
csg_edit_sequence_check $source "generic mouse translation" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{keypoint 0 0 0}
|
||||
{press sxy}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_bbox_translated $source $csg_special_mouse_target]
|
||||
}
|
||||
|
||||
# Every specialized menu entry must be accounted for. Exclusions are menu
|
||||
# headings, non-positional actions/settings, or the BOT triangle picker (tested
|
||||
# under Xmin because it needs Tk). A new entry without a mouse case or
|
||||
# explicit exclusion fails here.
|
||||
foreach {source ignored} {
|
||||
csg_lifecycle_pipe.s {
|
||||
{PIPE MENU} {Next Point} {Previous Point} {Delete Point}
|
||||
}
|
||||
csg_lifecycle_bot.s {
|
||||
{BOT MENU} {Pick Triangle} {Move Vertex List}
|
||||
{Split Edge} {Split Face} {Fuse Vertices} {Fuse Faces}
|
||||
{Delete Triangle} {Select Mode} {Select Orientation}
|
||||
{Set flags} {Set Face Thickness} {Set Face Mode}
|
||||
}
|
||||
csg_lifecycle_dsp.s {
|
||||
{DSP MENU} Name {Toggle Smooth} {Set Data Source}
|
||||
}
|
||||
csg_lifecycle_ebm.s {
|
||||
{EBM MENU} {File Name} {File Size (W N)}
|
||||
}
|
||||
csg_lifecycle_vol.s {
|
||||
{VOL MENU} {File Name} {File Size (X Y Z)}
|
||||
}
|
||||
csg_lifecycle_arbn.s {}
|
||||
csg_lifecycle_brep.s {}
|
||||
} {
|
||||
csg_edit_menu_inventory_check $source $ignored
|
||||
}
|
||||
|
||||
# A view-space request must remain view-space even when the editor's current
|
||||
# coordinate system is object-relative. This is the fast path underlying the
|
||||
# corresponding real mouse drag in the Xmin GUI test.
|
||||
set csg_saved_coords [rset var coords]
|
||||
set csg_saved_transform [rset var transform]
|
||||
if {[catch {
|
||||
Z
|
||||
e csg_lifecycle_bot.s
|
||||
sed csg_lifecycle_bot.s
|
||||
center 0 0 0
|
||||
rset var coords o
|
||||
rset var transform v
|
||||
knob -i -v aX 1
|
||||
if {[csg_edit_point_distance [center] {-1 0 0}] > 0.000001} {
|
||||
error "explicit view knob left center at [center]"
|
||||
}
|
||||
} csg_view_override_error]} {
|
||||
puts " FAIL: view-space translation with object coordinates ($csg_view_override_error)"
|
||||
} else {
|
||||
puts " PASS: view-space translation with object coordinates"
|
||||
}
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
rset var coords $csg_saved_coords
|
||||
rset var transform $csg_saved_transform
|
||||
|
||||
file delete -force $csg_data_file
|
||||
file delete -force $csg_dsp_file
|
||||
|
||||
|
||||
@@ -43,4 +43,37 @@ foreach {arb_type face expected_type} $arb_extrude_cases {
|
||||
arb_standard_storage_check $expected_type $prim
|
||||
}
|
||||
|
||||
# A one-inch extrusion must extend a face by 25.4 base millimeters through
|
||||
# both the direct libged command and MGED's interactive solid editor.
|
||||
set inch_in_mm 25.4
|
||||
set tolerance 0.001
|
||||
foreach mode {direct interactive} {
|
||||
set suffix "_inch_$mode"
|
||||
in_arb8 extrude $suffix
|
||||
set prim "extrude_arb8${suffix}.s"
|
||||
set base_x [lindex [db get $prim V1] 0]
|
||||
|
||||
units in
|
||||
if {$mode eq "direct"} {
|
||||
if {[catch {edarb extrude $prim 1234 1} result]} {
|
||||
error "inch edarb extrusion failed: $result"
|
||||
}
|
||||
} else {
|
||||
Z
|
||||
e $prim
|
||||
sed $prim
|
||||
if {[catch {extrude 1234 1} result]} {
|
||||
error "inch MGED extrusion failed: $result"
|
||||
}
|
||||
accept
|
||||
Z
|
||||
}
|
||||
units mm
|
||||
|
||||
set new_x [lindex [db get $prim V5] 0]
|
||||
if {abs($new_x - $base_x - $inch_in_mm) > $tolerance} {
|
||||
error "inch $mode extrusion moved V5 by [expr {$new_x - $base_x}] mm"
|
||||
}
|
||||
}
|
||||
|
||||
puts "*** 'extrude' testing completed ***"
|
||||
|
||||
@@ -31,6 +31,7 @@ in tor_pe.s tor 0 0 0 0 0 1 20 2
|
||||
prim_edit_check tor_pe.s "Set Radius 1" 30 r_a 30 -1
|
||||
prim_edit_check tor_pe.s "Set Radius 2" 5 r_h 5 -1
|
||||
prim_edit_mouse_check tor_pe.s "Set Radius 1" r_a 30 -1
|
||||
prim_edit_mouse_check tor_pe.s "Set Radius 2" r_h 5 -1
|
||||
kill tor_pe.s
|
||||
|
||||
puts "--- ELL (ellipsoid: A, B, C) ---"
|
||||
@@ -39,6 +40,8 @@ prim_edit_check ell_pe.s "Set A" 8 A 8 0
|
||||
prim_edit_check ell_pe.s "Set B" 6 B 6 1
|
||||
prim_edit_check ell_pe.s "Set C" 4 C 4 2
|
||||
prim_edit_mouse_check ell_pe.s "Set A" A 8 0
|
||||
prim_edit_mouse_check ell_pe.s "Set B" B 6 1
|
||||
prim_edit_mouse_check ell_pe.s "Set C" C 4 2
|
||||
kill ell_pe.s
|
||||
|
||||
puts "--- RPC (right parabolic cylinder: H, r) ---"
|
||||
@@ -46,6 +49,7 @@ in rpc_pe.s rpc 0 0 0 0 0 10 0 5 0 3
|
||||
prim_edit_check rpc_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check rpc_pe.s "Set r" 6 r 6 -1
|
||||
prim_edit_mouse_check rpc_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check rpc_pe.s "Set r" r 6 -1
|
||||
kill rpc_pe.s
|
||||
|
||||
puts "--- RHC (right hyperbolic cylinder: H, r, c) ---"
|
||||
@@ -54,6 +58,8 @@ prim_edit_check rhc_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check rhc_pe.s "Set r" 6 r 6 -1
|
||||
prim_edit_check rhc_pe.s "Set c" 3 c 3 -1
|
||||
prim_edit_mouse_check rhc_pe.s "Set r" r 6 -1
|
||||
prim_edit_mouse_check rhc_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check rhc_pe.s "Set c" c 3 -1
|
||||
kill rhc_pe.s
|
||||
|
||||
puts "--- EPA (elliptical paraboloid: H, r_1, r_2) ---"
|
||||
@@ -62,6 +68,8 @@ prim_edit_check epa_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check epa_pe.s "Set A" 8 r_1 8 -1
|
||||
prim_edit_check epa_pe.s "Set B" 4 r_2 4 -1
|
||||
prim_edit_mouse_check epa_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check epa_pe.s "Set A" r_1 8 -1
|
||||
prim_edit_mouse_check epa_pe.s "Set B" r_2 4 -1
|
||||
kill epa_pe.s
|
||||
|
||||
puts "--- EHY (elliptical hyperboloid: H, r_1, c) ---"
|
||||
@@ -70,6 +78,8 @@ prim_edit_check ehy_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check ehy_pe.s "Set A" 8 r_1 8 -1
|
||||
prim_edit_check ehy_pe.s "Set c" 3 c 3 -1
|
||||
prim_edit_mouse_check ehy_pe.s "Set A" r_1 8 -1
|
||||
prim_edit_mouse_check ehy_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check ehy_pe.s "Set c" c 3 -1
|
||||
kill ehy_pe.s
|
||||
|
||||
puts "--- PART (particle: H, r_v, r_h) ---"
|
||||
@@ -78,6 +88,8 @@ prim_edit_check part_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check part_pe.s "Set v" 4 r_v 4 -1
|
||||
prim_edit_check part_pe.s "Set h" 3 r_h 3 -1
|
||||
prim_edit_mouse_check part_pe.s "Set v" r_v 4 -1
|
||||
prim_edit_mouse_check part_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check part_pe.s "Set h" r_h 3 -1
|
||||
kill part_pe.s
|
||||
|
||||
puts "--- TGC (truncated general cone: H, A, B, C, D) ---"
|
||||
@@ -91,6 +103,10 @@ prim_edit_check tgc_pe.s "Set B" 3 B 3 1
|
||||
prim_edit_check tgc_pe.s "Set C" 3 C 3 0
|
||||
prim_edit_check tgc_pe.s "Set D" 4 D 4 1
|
||||
prim_edit_mouse_check tgc_pe.s "Set H" H 8 2
|
||||
prim_edit_mouse_check tgc_pe.s "Set A" A 4 0
|
||||
prim_edit_mouse_check tgc_pe.s "Set B" B 3 1
|
||||
prim_edit_mouse_check tgc_pe.s "Set C" C 3 0
|
||||
prim_edit_mouse_check tgc_pe.s "Set D" D 4 1
|
||||
kill tgc_pe.s
|
||||
|
||||
puts "--- ETO (elliptical torus: r, C, D) ---"
|
||||
@@ -100,6 +116,7 @@ prim_edit_check eto_pe.s "Set r" 8 r 8 -1
|
||||
prim_edit_check eto_pe.s "Set D" 1.5 r_d 1.5 -1
|
||||
prim_edit_mouse_check eto_pe.s "Set r" r 8 -1
|
||||
prim_edit_mouse_check eto_pe.s "Set C" C 5 0
|
||||
prim_edit_mouse_check eto_pe.s "Set D" r_d 1.5 -1
|
||||
kill eto_pe.s
|
||||
|
||||
puts "--- HYP (one-sheet hyperboloid: H, A, B, c) ---"
|
||||
@@ -111,6 +128,9 @@ prim_edit_check hyp_pe.s "Set A" 2 A 10 1
|
||||
prim_edit_check hyp_pe.s "Set B" 2 b 4 -1
|
||||
prim_edit_check hyp_pe.s "Set c" 0.5 bnr 0.25 -1
|
||||
prim_edit_mouse_check hyp_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check hyp_pe.s "Set A" A 10 1
|
||||
prim_edit_mouse_check hyp_pe.s "Set B" b 4 -1
|
||||
prim_edit_mouse_check hyp_pe.s "Set c" bnr 0.25 -1
|
||||
kill hyp_pe.s
|
||||
|
||||
puts "--- SUPERELL (superellipsoid: A, B, C) ---"
|
||||
@@ -119,6 +139,8 @@ prim_edit_check superell_pe.s "Set A" 5 A 5 0
|
||||
prim_edit_check superell_pe.s "Set B" 4 B 4 1
|
||||
prim_edit_check superell_pe.s "Set C" 3 C 3 2
|
||||
prim_edit_mouse_check superell_pe.s "Set A" A 5 0
|
||||
prim_edit_mouse_check superell_pe.s "Set B" B 4 1
|
||||
prim_edit_mouse_check superell_pe.s "Set C" C 3 2
|
||||
kill superell_pe.s
|
||||
|
||||
puts "--- CLINE (cylinder line: H, R, plate thickness) ---"
|
||||
@@ -129,6 +151,7 @@ prim_edit_check cline_pe.s "Set R" 4 R 4 -1
|
||||
prim_edit_check cline_pe.s "Set plate thickness" 0.4 T 0.4 -1
|
||||
prim_edit_mouse_check cline_pe.s "Set H" H 8 2
|
||||
prim_edit_mouse_check cline_pe.s "Set R" R 4 -1
|
||||
prim_edit_mouse_check cline_pe.s "Set plate thickness" T 0.4 -1
|
||||
kill cline_pe.s
|
||||
|
||||
puts "--- NMG (non-manifold geometry: Pick Edge, Move Edge, Next EU) ---"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
puts "*** Testing 'sed_reset' command ***"
|
||||
|
||||
proc sed_reset_check {primitive edit_commands} {
|
||||
e $primitive
|
||||
sed $primitive
|
||||
if {[status state] ne "SOL EDIT"} {
|
||||
error "$primitive entered [status state], not SOL EDIT"
|
||||
}
|
||||
|
||||
set original [get_sed]
|
||||
foreach command $edit_commands {
|
||||
uplevel #0 $command
|
||||
}
|
||||
if {[get_sed] eq $original} {
|
||||
error "$primitive edit did not change the working geometry"
|
||||
}
|
||||
|
||||
sed_reset
|
||||
if {[status state] ne "SOL EDIT"} {
|
||||
error "$primitive reset entered [status state], not SOL EDIT"
|
||||
}
|
||||
if {[get_sed] ne $original} {
|
||||
error "$primitive reset did not restore the original geometry"
|
||||
}
|
||||
|
||||
press reject
|
||||
if {[status state] ne "VIEWING"} {
|
||||
error "$primitive reject entered [status state], not VIEWING"
|
||||
}
|
||||
d $primitive
|
||||
}
|
||||
|
||||
if {[catch {
|
||||
in sed_reset_arb8.s arb8 \
|
||||
0 0 0 10 0 0 10 10 0 0 10 0 \
|
||||
0 0 10 10 0 10 10 10 10 0 10 10
|
||||
sed_reset_check sed_reset_arb8.s {
|
||||
{press {Move Faces}}
|
||||
{press {Move Face 1234}}
|
||||
{p 0 0 -1}
|
||||
}
|
||||
} failure]} {
|
||||
puts "FAIL: ARB8 face move reset ($failure)"
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
} else {
|
||||
puts "PASS: ARB8 face move reset"
|
||||
}
|
||||
|
||||
if {[catch {
|
||||
make sed_reset_cline.s cline
|
||||
sed_reset_check sed_reset_cline.s {
|
||||
{press {Move End H}}
|
||||
{p 3 4 12}
|
||||
}
|
||||
} failure]} {
|
||||
puts "FAIL: CLINE edit reset ($failure)"
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
} else {
|
||||
puts "PASS: CLINE edit reset"
|
||||
}
|
||||
|
||||
puts "PASS: 'sed_reset' testing completed"
|
||||
+76
-66
@@ -1,18 +1,18 @@
|
||||
if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND
|
||||
Xmin_RUN_EXECUTABLE AND SH_EXEC AND TARGET m35.g)
|
||||
set(_xmin_smoke "${CMAKE_CURRENT_SOURCE_DIR}/xmin_gui_smoke.sh")
|
||||
set(_xmin_smoke_environment
|
||||
set(_gui_smoke "${CMAKE_SOURCE_DIR}/regress/gui/gui_smoke.sh")
|
||||
set(_gui_smoke_environment
|
||||
"CMAKE_COMMAND=${CMAKE_COMMAND}"
|
||||
"LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/${LIB_DIR}"
|
||||
"XMIN_TEST_SHELL=${CMAKE_CURRENT_SOURCE_DIR}/xmin_test.sh"
|
||||
"GUI_TEST_SHELL=${CMAKE_SOURCE_DIR}/regress/gui/gui_test.sh"
|
||||
)
|
||||
set(_xmin_test_db "${CMAKE_BINARY_DIR}/${DATA_DIR}/db/m35.g")
|
||||
set(_xmin_gui_library "${CMAKE_CURRENT_SOURCE_DIR}/xmin_gui_test.tcl")
|
||||
set(_xmin_tcl_runner "${CMAKE_CURRENT_SOURCE_DIR}/xmin_tcl_gui_test.sh")
|
||||
set(_gui_test_db "${CMAKE_BINARY_DIR}/${DATA_DIR}/db/m35.g")
|
||||
set(_gui_test_library "${CMAKE_SOURCE_DIR}/regress/gui/gui_test.tcl")
|
||||
set(_gui_tcl_runner "${CMAKE_SOURCE_DIR}/regress/gui/gui_tcl_test.sh")
|
||||
|
||||
if(TARGET mged AND TARGET dm-tkswrast AND TARGET dm-X AND TARGET dm-ogl
|
||||
AND TARGET icv AND TARGET pixcrop AND TARGET rt)
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-mged-xmin-gui-edit
|
||||
TIMEOUT 600
|
||||
ENVIRONMENT
|
||||
@@ -25,11 +25,10 @@ if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND
|
||||
"MGED_GUI_MANIFEST=${CMAKE_CURRENT_SOURCE_DIR}/mged/mged_gui_menu_manifest.txt"
|
||||
"MGED_PIPE_ORACLE=${CMAKE_CURRENT_SOURCE_DIR}/mged/xmin_gui_pipe_oracle.tcl"
|
||||
"MGED_RT_BIN=$<TARGET_FILE:rt>"
|
||||
"MGED_XMIN_ACTIVE_SESSION=1"
|
||||
"MGED_TEST_SHELL=${SH_EXEC}"
|
||||
"MGED_XMIN_RC=${CMAKE_CURRENT_SOURCE_DIR}/mged/xmin_gui_edit.tcl"
|
||||
"GUI_TEST_SHELL=${CMAKE_SOURCE_DIR}/regress/gui/gui_test.sh"
|
||||
"MGED_GUI_RC=${CMAKE_CURRENT_SOURCE_DIR}/mged/xmin_gui_edit.tcl"
|
||||
"PIXCROP_BIN=$<TARGET_FILE:pixcrop>"
|
||||
"XMIN_GUI_LIBRARY=${CMAKE_SOURCE_DIR}/regress/xmin/xmin_gui_test.tcl"
|
||||
"GUI_TEST_LIBRARY=${_gui_test_library}"
|
||||
COMMAND "${SH_EXEC}" "${CMAKE_CURRENT_SOURCE_DIR}/mged/mged_xmin_gui.sh"
|
||||
)
|
||||
brlcad_regression_test(regress-mged-xmin-gui-edit
|
||||
@@ -38,48 +37,48 @@ if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND
|
||||
endif()
|
||||
|
||||
if(TARGET mged AND TARGET dm-tkswrast)
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-mged-xmin-gui-controls
|
||||
TIMEOUT 180
|
||||
ENVIRONMENT ${_xmin_smoke_environment}
|
||||
"XMIN_GUI_LIBRARY=${_xmin_gui_library}"
|
||||
COMMAND "${SH_EXEC}" "${_xmin_tcl_runner}"
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"GUI_TEST_LIBRARY=${_gui_test_library}"
|
||||
COMMAND "${SH_EXEC}" "${_gui_tcl_runner}"
|
||||
mged-controls $<TARGET_FILE:mged> --gui --dm-type tkswrast
|
||||
--rcfile "${CMAKE_CURRENT_SOURCE_DIR}/mged/xmin_gui_controls.tcl"
|
||||
--geom 680x520+0+0 --ggeom 512x512+700+0
|
||||
"${_xmin_test_db}"
|
||||
"${_gui_test_db}"
|
||||
)
|
||||
brlcad_regression_test(regress-mged-xmin-gui-controls
|
||||
"mged;dm-tkswrast;m35.g" STAND_ALONE TEST_DEFINED)
|
||||
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-mged-xmin-gui-workflows
|
||||
TIMEOUT 300
|
||||
ENVIRONMENT ${_xmin_smoke_environment}
|
||||
"XMIN_GUI_LIBRARY=${_xmin_gui_library}"
|
||||
COMMAND "${SH_EXEC}" "${_xmin_tcl_runner}"
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"GUI_TEST_LIBRARY=${_gui_test_library}"
|
||||
COMMAND "${SH_EXEC}" "${_gui_tcl_runner}"
|
||||
mged-workflows $<TARGET_FILE:mged> --gui --dm-type tkswrast
|
||||
--rcfile "${CMAKE_CURRENT_SOURCE_DIR}/mged/xmin_gui_workflows.tcl"
|
||||
--geom 680x520+0+0 --ggeom 512x512+700+0
|
||||
"${_xmin_test_db}"
|
||||
"${_gui_test_db}"
|
||||
)
|
||||
brlcad_regression_test(regress-mged-xmin-gui-workflows
|
||||
"mged;dm-tkswrast;m35.g" STAND_ALONE TEST_DEFINED)
|
||||
|
||||
function(mged_add_xmin_gui_fixture test_name dependencies)
|
||||
string(REPLACE "-" "_" script_name "${test_name}")
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-mged-xmin-gui-${test_name}
|
||||
TIMEOUT 180
|
||||
ENVIRONMENT ${_xmin_smoke_environment}
|
||||
"MGED_XMIN_GUI_LIBRARY=${CMAKE_CURRENT_SOURCE_DIR}/mged/xmin_gui_test.tcl"
|
||||
"XMIN_GUI_LIBRARY=${_xmin_gui_library}"
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"MGED_GUI_TEST_LIBRARY=${CMAKE_CURRENT_SOURCE_DIR}/mged/xmin_gui_test.tcl"
|
||||
"GUI_TEST_LIBRARY=${_gui_test_library}"
|
||||
${ARGN}
|
||||
COMMAND "${SH_EXEC}" "${_xmin_tcl_runner}"
|
||||
COMMAND "${SH_EXEC}" "${_gui_tcl_runner}"
|
||||
mged-${test_name} $<TARGET_FILE:mged> --gui --dm-type tkswrast
|
||||
--rcfile "${CMAKE_CURRENT_SOURCE_DIR}/mged/xmin_gui_${script_name}.tcl"
|
||||
--geom 680x520+0+0 --ggeom 512x512+700+0
|
||||
"${_xmin_test_db}"
|
||||
"${_gui_test_db}"
|
||||
)
|
||||
brlcad_regression_test(regress-mged-xmin-gui-${test_name}
|
||||
"${dependencies}" STAND_ALONE TEST_DEFINED)
|
||||
@@ -94,6 +93,7 @@ if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND
|
||||
"PLOT3_ASC_BIN=$<TARGET_FILE:plot3-asc>"
|
||||
)
|
||||
mged_add_xmin_gui_fixture(help "mged;dm-tkswrast;m35.g")
|
||||
mged_add_xmin_gui_fixture(edit-interaction "mged;dm-tkswrast;m35.g")
|
||||
mged_add_xmin_gui_fixture(bot "mged;dm-tkswrast;m35.g")
|
||||
mged_add_xmin_gui_fixture(editors "mged;dm-tkswrast;m35.g")
|
||||
mged_add_xmin_gui_fixture(query-pattern "mged;dm-tkswrast;m35.g")
|
||||
@@ -105,70 +105,82 @@ if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND
|
||||
endif()
|
||||
|
||||
if(TARGET archer)
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-archer-xmin-smoke
|
||||
TIMEOUT 180
|
||||
ENVIRONMENT ${_xmin_smoke_environment}
|
||||
"XMIN_SMOKE_ACTION=${CMAKE_CURRENT_SOURCE_DIR}/archer_action.sh"
|
||||
"XMIN_MIN_CHANGED_BYTES=10000"
|
||||
COMMAND "${SH_EXEC}" "${_xmin_smoke}" "Archer ${BRLCAD_VERSION}"
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"GUI_SMOKE_ACTION=${CMAKE_CURRENT_SOURCE_DIR}/archer_action.sh"
|
||||
"GUI_MIN_CHANGED_BYTES=10000"
|
||||
COMMAND "${SH_EXEC}" "${_gui_smoke}" "Archer ${BRLCAD_VERSION}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/archer_smoke.sh"
|
||||
$<TARGET_FILE:archer> "${_xmin_test_db}"
|
||||
$<TARGET_FILE:archer> "${_gui_test_db}"
|
||||
)
|
||||
brlcad_regression_test(regress-archer-xmin-smoke
|
||||
"archer;m35.g" STAND_ALONE TEST_DEFINED)
|
||||
|
||||
if(TARGET bwish)
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-archer-xmin-gui
|
||||
TIMEOUT 180
|
||||
ENVIRONMENT ${_xmin_smoke_environment}
|
||||
"XMIN_GUI_LIBRARY=${_xmin_gui_library}"
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"GUI_TEST_LIBRARY=${_gui_test_library}"
|
||||
"ARCHER_LAUNCH=${CMAKE_BINARY_DIR}/${DATA_DIR}/tclscripts/archer/init/archer_launch.tcl"
|
||||
"ARCHER_TEST_DATABASE=${_xmin_test_db}"
|
||||
"ARCHER_TEST_DATABASE=${_gui_test_db}"
|
||||
"ARCHER_MENU_MANIFEST=${CMAKE_CURRENT_SOURCE_DIR}/archer_menu_manifest.txt"
|
||||
COMMAND "${SH_EXEC}" "${_xmin_tcl_runner}" archer
|
||||
COMMAND "${SH_EXEC}" "${_gui_tcl_runner}" archer
|
||||
$<TARGET_FILE:bwish> "${CMAKE_CURRENT_SOURCE_DIR}/archer_xmin_gui.tcl"
|
||||
)
|
||||
brlcad_regression_test(regress-archer-xmin-gui
|
||||
"archer;bwish;m35.g" STAND_ALONE TEST_DEFINED)
|
||||
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-archer-embedded-xmin-gui
|
||||
TIMEOUT 180
|
||||
ENVIRONMENT ${_xmin_smoke_environment}
|
||||
"XMIN_GUI_LIBRARY=${_xmin_gui_library}"
|
||||
COMMAND "${SH_EXEC}" "${_xmin_tcl_runner}" archer-embedded
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"GUI_TEST_LIBRARY=${_gui_test_library}"
|
||||
COMMAND "${SH_EXEC}" "${_gui_tcl_runner}" archer-embedded
|
||||
$<TARGET_FILE:bwish>
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/archer_embedded_xmin_gui.tcl"
|
||||
)
|
||||
brlcad_regression_test(regress-archer-embedded-xmin-gui
|
||||
"archer;bwish" STAND_ALONE TEST_DEFINED)
|
||||
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-archer-geometry-xmin-gui
|
||||
TIMEOUT 120
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"GUI_TEST_LIBRARY=${_gui_test_library}"
|
||||
COMMAND "${SH_EXEC}" "${_gui_tcl_runner}" archer-geometry
|
||||
$<TARGET_FILE:bwish>
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/archer_geometry_xmin_gui.tcl"
|
||||
)
|
||||
brlcad_regression_test(regress-archer-geometry-xmin-gui
|
||||
"archer;bwish" STAND_ALONE TEST_DEFINED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(TARGET rtwizard)
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-rtwizard-xmin-smoke
|
||||
TIMEOUT 180
|
||||
ENVIRONMENT ${_xmin_smoke_environment}
|
||||
"XMIN_SMOKE_ACTION=${CMAKE_CURRENT_SOURCE_DIR}/rtwizard_action.sh"
|
||||
"XMIN_MIN_CHANGED_BYTES=5000"
|
||||
COMMAND "${SH_EXEC}" "${_xmin_smoke}" RtWizard
|
||||
$<TARGET_FILE:rtwizard> --gui -i "${_xmin_test_db}" -t A
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"GUI_SMOKE_ACTION=${CMAKE_CURRENT_SOURCE_DIR}/rtwizard_action.sh"
|
||||
"GUI_MIN_CHANGED_BYTES=5000"
|
||||
COMMAND "${SH_EXEC}" "${_gui_smoke}" RtWizard
|
||||
$<TARGET_FILE:rtwizard> --gui -i "${_gui_test_db}" -t A
|
||||
)
|
||||
brlcad_regression_test(regress-rtwizard-xmin-smoke
|
||||
"rtwizard;m35.g" STAND_ALONE TEST_DEFINED)
|
||||
|
||||
if(TARGET bwish)
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-rtwizard-xmin-gui
|
||||
TIMEOUT 180
|
||||
ENVIRONMENT ${_xmin_smoke_environment}
|
||||
"XMIN_GUI_LIBRARY=${_xmin_gui_library}"
|
||||
"RTWIZARD_TEST_DATABASE=${_xmin_test_db}"
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"GUI_TEST_LIBRARY=${_gui_test_library}"
|
||||
"RTWIZARD_TEST_DATABASE=${_gui_test_db}"
|
||||
"RTWIZARD_MENU_MANIFEST=${CMAKE_CURRENT_SOURCE_DIR}/rtwizard_menu_manifest.txt"
|
||||
COMMAND "${SH_EXEC}" "${_xmin_tcl_runner}" rtwizard
|
||||
COMMAND "${SH_EXEC}" "${_gui_tcl_runner}" rtwizard
|
||||
$<TARGET_FILE:bwish> "${CMAKE_CURRENT_SOURCE_DIR}/rtwizard_xmin_gui.tcl"
|
||||
)
|
||||
brlcad_regression_test(regress-rtwizard-xmin-gui
|
||||
@@ -179,15 +191,15 @@ if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND
|
||||
# qged is still evolving, so keep this fixture deliberately narrow: prove
|
||||
# that Qt starts, the console accepts a command, and OpenGL redraws.
|
||||
if(TARGET qged)
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-qged-xmin-smoke
|
||||
TIMEOUT 180
|
||||
ENVIRONMENT ${_xmin_smoke_environment}
|
||||
"XMIN_SMOKE_ACTION=${CMAKE_CURRENT_SOURCE_DIR}/qged_action.sh"
|
||||
"XMIN_MIN_CHANGED_BYTES=5000"
|
||||
COMMAND "${SH_EXEC}" "${_xmin_smoke}" QGED
|
||||
ENVIRONMENT ${_gui_smoke_environment}
|
||||
"GUI_SMOKE_ACTION=${CMAKE_CURRENT_SOURCE_DIR}/qged_action.sh"
|
||||
"GUI_MIN_CHANGED_BYTES=5000"
|
||||
COMMAND "${SH_EXEC}" "${_gui_smoke}" QGED
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/qged_smoke.sh"
|
||||
$<TARGET_FILE:qged> "${_xmin_test_db}"
|
||||
$<TARGET_FILE:qged> "${_gui_test_db}"
|
||||
)
|
||||
brlcad_regression_test(regress-qged-xmin-smoke
|
||||
"qged;m35.g" STAND_ALONE TEST_DEFINED)
|
||||
@@ -197,10 +209,11 @@ endif()
|
||||
cmakefiles(
|
||||
CMakeLists.txt
|
||||
README.md
|
||||
xmin_gui_smoke.sh
|
||||
xmin_gui_ctl.sh
|
||||
archer_action.sh
|
||||
archer_smoke.sh
|
||||
archer_embedded_xmin_gui.tcl
|
||||
archer_geometry_xmin_gui.tcl
|
||||
archer_menu_manifest.txt
|
||||
archer_xmin_gui.tcl
|
||||
qged_action.sh
|
||||
@@ -208,27 +221,24 @@ cmakefiles(
|
||||
rtwizard_action.sh
|
||||
rtwizard_menu_manifest.txt
|
||||
rtwizard_xmin_gui.tcl
|
||||
xmin_gui_test.tcl
|
||||
xmin_test.sh
|
||||
xmin_test.tcl
|
||||
xmin_tcl_gui_test.sh
|
||||
mged/MGED_GUI_TEST_COVERAGE.md
|
||||
mged/mged_gui_menu_manifest.txt
|
||||
mged/mged_xmin_gui.sh
|
||||
mged/xmin_gui_bot.tcl
|
||||
mged/xmin_gui_controls.tcl
|
||||
mged/xmin_gui_edit.tcl
|
||||
mged/xmin_gui_edit_interaction.tcl
|
||||
mged/xmin_gui_editors.tcl
|
||||
mged/xmin_gui_help.tcl
|
||||
mged/xmin_gui_lod.tcl
|
||||
mged/xmin_gui_overlaps.tcl
|
||||
mged/xmin_gui_pipe_oracle.tcl
|
||||
mged/xmin_gui_query_pattern.tcl
|
||||
mged/xmin_gui_render_outputs.tcl
|
||||
mged/xmin_gui_search_exec.tcl
|
||||
mged/xmin_gui_shotvis.tcl
|
||||
mged/xmin_gui_test.tcl
|
||||
mged/xmin_gui_workflows.tcl
|
||||
mged/xmin_gui_edit.tcl
|
||||
mged/xmin_gui_pipe_oracle.tcl
|
||||
)
|
||||
|
||||
# Local Variables:
|
||||
|
||||
+12
-15
@@ -13,16 +13,13 @@ and toolkit code must interpret consistently.
|
||||
|
||||
## Shared architecture
|
||||
|
||||
The support has three layers:
|
||||
|
||||
1. `brlcad_add_xmin_test` owns the private-server lifecycle, fixed screen,
|
||||
environment, timeout, and CTest registration.
|
||||
2. `xmin_gui_smoke.sh` owns the application lifecycle: launch, resolve the
|
||||
mapped top-level to a stable window ID, wait for rendering to settle,
|
||||
capture, run an optional action, compare captures, and close cleanly.
|
||||
3. Application fixtures own their semantic oracle. Tk applications source
|
||||
`xmin_gui_test.tcl` for widget and menu discovery. XTEST action scripts
|
||||
drive paths that must traverse the actual X input protocol.
|
||||
The platform-neutral helpers and controller contract are documented in
|
||||
[GUI regression support](../gui/README.md). `brlcad_add_gui_test` currently
|
||||
selects the Xmin backend, which starts a private server at a fixed screen
|
||||
size. `xmin_gui_ctl.sh` translates controller commands to `xminctl`.
|
||||
Application fixtures supply their own semantic checks; XTEST action scripts
|
||||
exercise real input dispatch. MGED's deep fixture includes X11 and GLX
|
||||
display managers and remains specific to this backend.
|
||||
|
||||
Resolving a window name once is important for Qt, which may create mapped and
|
||||
unmapped helper windows with the same title. Repeating a title lookup can
|
||||
@@ -97,7 +94,7 @@ the Qt application starts, its console accepts `draw all.g`, and the OpenGL
|
||||
view changes. qged is not yet stable enough for a menu or widget compatibility
|
||||
manifest.
|
||||
|
||||
The libtclcad Itcl 3 tests complement application fixtures by loading the GUI
|
||||
The libtclcad Itcl 4 tests complement application fixtures by loading the GUI
|
||||
package graph in both `btclsh` and `bwish`, checking representative Sdialogs,
|
||||
Swidgets, DataUtils, and cadwidgets behavior, and repeating package and object
|
||||
initialization in independent, destroyed, and replacement Tcl interpreters.
|
||||
@@ -114,13 +111,13 @@ widget-state assertion.
|
||||
For a conventional executable:
|
||||
|
||||
```
|
||||
brlcad_add_xmin_test(
|
||||
brlcad_add_gui_test(
|
||||
NAME regress-example-xmin-smoke
|
||||
TIMEOUT 180
|
||||
ENVIRONMENT
|
||||
"XMIN_TEST_SHELL=${CMAKE_CURRENT_SOURCE_DIR}/xmin_test.sh"
|
||||
"XMIN_SMOKE_ACTION=${CMAKE_CURRENT_SOURCE_DIR}/example_action.sh"
|
||||
COMMAND "${SH_EXEC}" "${CMAKE_CURRENT_SOURCE_DIR}/xmin_gui_smoke.sh"
|
||||
"GUI_TEST_SHELL=${CMAKE_SOURCE_DIR}/regress/gui/gui_test.sh"
|
||||
"GUI_SMOKE_ACTION=${CMAKE_CURRENT_SOURCE_DIR}/example_action.sh"
|
||||
COMMAND "${SH_EXEC}" "${CMAKE_SOURCE_DIR}/regress/gui/gui_smoke.sh"
|
||||
"Expected title" $<TARGET_FILE:example>
|
||||
)
|
||||
```
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
set -eu
|
||||
|
||||
: "${XMIN_TEST_SHELL:?XMIN_TEST_SHELL is required}"
|
||||
. "$XMIN_TEST_SHELL"
|
||||
: "${GUI_TEST_SHELL:?GUI_TEST_SHELL is required}"
|
||||
. "$GUI_TEST_SHELL"
|
||||
|
||||
window=$1
|
||||
geometry=$("$XMIN_CTL" geometry "$window") ||
|
||||
xmin_fail "could not query Archer window geometry"
|
||||
geometry=$("$GUI_TEST_CTL" geometry "$window") ||
|
||||
gui_fail "could not query Archer window geometry"
|
||||
set -- $geometry
|
||||
width=$3
|
||||
height=$4
|
||||
@@ -16,9 +16,9 @@ height=$4
|
||||
# relative to the live geometry so the action is independent of screen size.
|
||||
command_x=$((width / 4))
|
||||
command_y=$((height - 27))
|
||||
"$XMIN_CTL" click "$window" "$command_x" "$command_y" 1
|
||||
"$XMIN_CTL" type "draw all.g"
|
||||
"$XMIN_CTL" key enter
|
||||
"$GUI_TEST_CTL" click "$window" "$command_x" "$command_y" 1
|
||||
"$GUI_TEST_CTL" type "draw all.g"
|
||||
"$GUI_TEST_CTL" key enter
|
||||
ARCHER_DRAW_SETTLE_SECONDS=${ARCHER_DRAW_SETTLE_SECONDS:-1}
|
||||
sleep "$ARCHER_DRAW_SETTLE_SECONDS"
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
# information.
|
||||
#
|
||||
###
|
||||
if {![info exists ::env(XMIN_GUI_LIBRARY)]} {
|
||||
puts stderr "XMIN_GUI_LIBRARY is required"
|
||||
if {![info exists ::env(GUI_TEST_LIBRARY)]} {
|
||||
puts stderr "GUI_TEST_LIBRARY is required"
|
||||
exit 2
|
||||
}
|
||||
source $::env(XMIN_GUI_LIBRARY)
|
||||
set ::env(ARCHER_PREFS_FILE) [file join $::env(XMIN_TEST_DIR) .archerrc]
|
||||
source $::env(GUI_TEST_LIBRARY)
|
||||
set ::env(ARCHER_PREFS_FILE) [file join $::env(GUI_TEST_DIR) .archerrc]
|
||||
|
||||
# ArcherCore supports embedding in another Itk widget. Its constructor
|
||||
# currently performs a synchronous database load after one update, so inspect
|
||||
@@ -41,16 +41,16 @@ if {[catch {package require Archer 1.0} message options]} {
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
::xmin::test::capture_background_errors
|
||||
::gui::test::capture_background_errors
|
||||
|
||||
proc ::archer_embedded_check {} {
|
||||
if {[catch {
|
||||
set application .embedded
|
||||
::xmin::test::require {[winfo exists $application]} \
|
||||
::gui::test::require {[winfo exists $application]} \
|
||||
"embedded Archer widget was not created"
|
||||
|
||||
set inventory [::xmin::test::menu_inventory $application]
|
||||
::xmin::test::write embedded_menu_inventory $inventory
|
||||
set inventory [::gui::test::menu_inventory $application]
|
||||
::gui::test::write embedded_menu_inventory $inventory
|
||||
|
||||
foreach labels {
|
||||
{File Save}
|
||||
@@ -66,8 +66,8 @@ proc ::archer_embedded_check {} {
|
||||
{Raytrace rt 512x512}
|
||||
{Help {About Archer...}}
|
||||
} {
|
||||
::xmin::test::require {
|
||||
[::xmin::test::find_menu_entry $application $labels] ne ""
|
||||
::gui::test::require {
|
||||
[::gui::test::find_menu_entry $application $labels] ne ""
|
||||
} "missing embedded Archer menu entry: [join $labels { > }]"
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ proc ::archer_embedded_check {} {
|
||||
{File Revert}
|
||||
{File Raytrace}
|
||||
} {
|
||||
::xmin::test::require {
|
||||
[::xmin::test::find_menu_entry $application $labels] eq ""
|
||||
::gui::test::require {
|
||||
[::gui::test::find_menu_entry $application $labels] eq ""
|
||||
} "unexpected embedded Archer menu entry: [join $labels { > }]"
|
||||
}
|
||||
} message options]} {
|
||||
@@ -90,7 +90,7 @@ proc ::archer_embedded_check {} {
|
||||
}
|
||||
|
||||
catch {update}
|
||||
lassign [::xmin::test::check_background_errors 0 \
|
||||
lassign [::gui::test::check_background_errors 0 \
|
||||
"PASS: embedded Archer menu construction"] status result
|
||||
puts $result
|
||||
if {$status != 0} {
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
# A R C H E R _ G E O M E T R Y _ X M I N _ G U I . T C L
|
||||
# BRL-CAD
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
#
|
||||
###
|
||||
if {![info exists ::env(GUI_TEST_LIBRARY)]} {
|
||||
puts stderr "GUI_TEST_LIBRARY is required"
|
||||
exit 2
|
||||
}
|
||||
source $::env(GUI_TEST_LIBRARY)
|
||||
set ::env(ARCHER_PREFS_FILE) [file join $::env(GUI_TEST_DIR) .archerrc]
|
||||
|
||||
proc archer_geometry_preferences {{geometry ""}} {
|
||||
set channel [open $::env(ARCHER_PREFS_FILE) w]
|
||||
if {$geometry ne ""} {
|
||||
puts $channel [list set mWindowGeometry $geometry]
|
||||
}
|
||||
close $channel
|
||||
}
|
||||
|
||||
proc archer_geometry_saved {} {
|
||||
set channel [open $::env(ARCHER_PREFS_FILE) r]
|
||||
set contents [read $channel]
|
||||
close $channel
|
||||
if {[regexp -line {^set mWindowGeometry (.+)$} $contents -> geometry]} {
|
||||
return $geometry
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
proc archer_geometry_settle {} {
|
||||
# Allow MapNotify and the deferred geometry restore to reach the event loop.
|
||||
set settle_delay_ms 100
|
||||
after $settle_delay_ms [list set ::archer_geometry_settled 1]
|
||||
vwait ::archer_geometry_settled
|
||||
update
|
||||
::gui::test::require_no_background_errors
|
||||
}
|
||||
|
||||
if {[catch {
|
||||
package require Archer 1.0
|
||||
::gui::test::capture_background_errors
|
||||
wm withdraw .
|
||||
|
||||
set saved_geometry 900x650+120+90
|
||||
set startup_geometry 1000x700+20+30
|
||||
set updated_geometry 950x680+60+70
|
||||
set default_geometry 920x660+40+50
|
||||
|
||||
archer_geometry_preferences $saved_geometry
|
||||
Archer .unmapped
|
||||
::gui::test::require {[wm state .unmapped] eq "withdrawn"} \
|
||||
"startup fixture unexpectedly showed its window"
|
||||
::itcl::delete object .unmapped
|
||||
archer_geometry_settle
|
||||
::gui::test::require {[archer_geometry_saved] eq $saved_geometry} \
|
||||
"closing an unmapped Archer replaced its saved geometry"
|
||||
|
||||
archer_geometry_preferences
|
||||
Archer .unmapped_new
|
||||
::itcl::delete object .unmapped_new
|
||||
archer_geometry_settle
|
||||
::gui::test::require {[archer_geometry_saved] eq ""} \
|
||||
"closing an unmapped Archer saved an unfinished layout size"
|
||||
|
||||
archer_geometry_preferences $saved_geometry
|
||||
Archer .restore
|
||||
.restore configure -geometry $startup_geometry
|
||||
wm geometry .restore $startup_geometry
|
||||
event generate [.restore component hpane] <Map>
|
||||
archer_geometry_settle
|
||||
::gui::test::require {[wm geometry .restore] eq $startup_geometry} \
|
||||
"a child Map event restored the main window's geometry prematurely"
|
||||
|
||||
wm deiconify .restore
|
||||
archer_geometry_settle
|
||||
::gui::test::require {[wm geometry .restore] eq $saved_geometry} \
|
||||
"mapping the main window did not restore its saved geometry"
|
||||
|
||||
wm geometry .restore $updated_geometry
|
||||
event generate [.restore component hpane] <Map>
|
||||
archer_geometry_settle
|
||||
::gui::test::require {[wm geometry .restore] eq $updated_geometry} \
|
||||
"a later child Map event reset the resized main window"
|
||||
wm withdraw .restore
|
||||
::itcl::delete object .restore
|
||||
archer_geometry_settle
|
||||
::gui::test::require {[archer_geometry_saved] eq $updated_geometry} \
|
||||
"closing a previously mapped window did not save its latest geometry"
|
||||
|
||||
archer_geometry_preferences
|
||||
Archer .default
|
||||
wm geometry .default $default_geometry
|
||||
wm deiconify .default
|
||||
archer_geometry_settle
|
||||
::gui::test::require {[wm geometry .default] eq $default_geometry} \
|
||||
"an empty geometry option reset the window to its layout size"
|
||||
wm withdraw .default
|
||||
::itcl::delete object .default
|
||||
archer_geometry_settle
|
||||
} message options]} {
|
||||
puts stderr $message
|
||||
if {[dict exists $options -errorinfo]} {
|
||||
puts stderr [dict get $options -errorinfo]
|
||||
}
|
||||
puts "FAIL: Archer window geometry regression"
|
||||
exit 1
|
||||
}
|
||||
|
||||
puts "PASS: Archer window geometry restoration and startup cancellation"
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# tab-width: 8
|
||||
# mode: Tcl
|
||||
# tcl-indent-level: 4
|
||||
# indent-tabs-mode: t
|
||||
# End:
|
||||
# ex: shiftwidth=4 tabstop=8
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
set -eu
|
||||
|
||||
: "${XMIN_ARTIFACT_DIR:?XMIN_ARTIFACT_DIR is required}"
|
||||
: "${GUI_ARTIFACT_DIR:?GUI_ARTIFACT_DIR is required}"
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: $0 archer [argument ...]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
ARCHER_PREFS_FILE="$XMIN_ARTIFACT_DIR/.archerrc"
|
||||
ARCHER_PREFS_FILE="$GUI_ARTIFACT_DIR/.archerrc"
|
||||
export ARCHER_PREFS_FILE
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -18,14 +18,15 @@
|
||||
# information.
|
||||
#
|
||||
###
|
||||
if {![info exists ::env(XMIN_GUI_LIBRARY)] ||
|
||||
if {![info exists ::env(GUI_TEST_LIBRARY)] ||
|
||||
![info exists ::env(ARCHER_LAUNCH)] ||
|
||||
![info exists ::env(ARCHER_TEST_DATABASE)]} {
|
||||
puts stderr "XMIN_GUI_LIBRARY, ARCHER_LAUNCH, and ARCHER_TEST_DATABASE are required"
|
||||
puts stderr "GUI_TEST_LIBRARY, ARCHER_LAUNCH, and ARCHER_TEST_DATABASE are required"
|
||||
exit 2
|
||||
}
|
||||
source $::env(XMIN_GUI_LIBRARY)
|
||||
set ::env(ARCHER_PREFS_FILE) [file join $::env(XMIN_TEST_DIR) .archerrc]
|
||||
source $::env(GUI_TEST_LIBRARY)
|
||||
source [file join [file dirname $::env(GUI_TEST_LIBRARY)] sketch_test.tcl]
|
||||
set ::env(ARCHER_PREFS_FILE) [file join $::env(GUI_TEST_DIR) .archerrc]
|
||||
|
||||
namespace eval ::archer::xmin {
|
||||
variable application ""
|
||||
@@ -44,7 +45,7 @@ proc ::archer::xmin::finish {status message} {
|
||||
}
|
||||
catch {destroy .}
|
||||
catch {update}
|
||||
lassign [::xmin::test::check_background_errors $status $message] \
|
||||
lassign [::gui::test::check_background_errors $status $message] \
|
||||
status message
|
||||
puts $message
|
||||
if {$status != 0} {
|
||||
@@ -55,7 +56,7 @@ proc ::archer::xmin::finish {status message} {
|
||||
|
||||
proc ::archer::xmin::toplevels {} {
|
||||
set toplevels {}
|
||||
foreach widget [linsert [::xmin::test::descendants .] 0 .] {
|
||||
foreach widget [linsert [::gui::test::descendants .] 0 .] {
|
||||
if {[winfo toplevel $widget] eq $widget} {
|
||||
lappend toplevels $widget
|
||||
}
|
||||
@@ -88,18 +89,18 @@ proc ::archer::xmin::exercise_dialog {root labels {expected_title ""}} {
|
||||
variable dialog_timeout_ms
|
||||
set dialog_seen ""
|
||||
after $dialog_poll_delay_ms ::archer::xmin::dismiss_dialog
|
||||
::xmin::test::invoke_menu_entry $root $labels
|
||||
::gui::test::invoke_menu_entry $root $labels
|
||||
if {$dialog_seen eq ""} {
|
||||
set timeout [after $dialog_timeout_ms \
|
||||
[list set ::archer::xmin::dialog_seen $dialog_timeout_marker]]
|
||||
vwait ::archer::xmin::dialog_seen
|
||||
after cancel $timeout
|
||||
}
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
$dialog_seen ne "" && $dialog_seen ne $dialog_timeout_marker} \
|
||||
"menu entry did not display a dialog: [join $labels { > }]"
|
||||
if {$expected_title ne ""} {
|
||||
::xmin::test::require {$dialog_seen eq $expected_title} \
|
||||
::gui::test::require {$dialog_seen eq $expected_title} \
|
||||
"unexpected dialog title '$dialog_seen', expected '$expected_title'"
|
||||
}
|
||||
}
|
||||
@@ -112,7 +113,7 @@ proc ::archer::xmin::compare_manifest {actual} {
|
||||
set expected [string trim [read $channel]]
|
||||
close $channel
|
||||
if {$actual ne $expected} {
|
||||
::xmin::test::write menu_inventory_actual $actual
|
||||
::gui::test::write menu_inventory_actual $actual
|
||||
error "live Archer menu inventory differs from its manifest"
|
||||
}
|
||||
}
|
||||
@@ -138,7 +139,7 @@ proc ::archer::xmin::exercise_object_lifecycle {
|
||||
error "$class $cycle initialization failed: $message"
|
||||
}
|
||||
update
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength [info commands $object]] == 1 &&
|
||||
[winfo exists $object]
|
||||
} "$class $cycle construction did not retain its object and window"
|
||||
@@ -149,7 +150,7 @@ proc ::archer::xmin::exercise_object_lifecycle {
|
||||
error "$class $cycle destruction failed: $message"
|
||||
}
|
||||
update
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength [info commands $object]] == 0 &&
|
||||
![winfo exists $object]
|
||||
} "$class $cycle destruction retained its object or window"
|
||||
@@ -182,8 +183,8 @@ proc ::archer::xmin::require_arb_standard_storage {ged geometry_name primitive}
|
||||
set expected [$ged get $geometry_name [lindex $group 0]]
|
||||
foreach attribute [lrange $group 1 end] {
|
||||
set actual [$ged get $geometry_name $attribute]
|
||||
::xmin::test::require {
|
||||
[::xmin::test::equivalent_values $actual $expected]
|
||||
::gui::test::require {
|
||||
[::gui::test::equivalent_values $actual $expected]
|
||||
} "$primitive storage is nonstandard: [lindex $group 0]=$expected, $attribute=$actual"
|
||||
}
|
||||
}
|
||||
@@ -208,8 +209,8 @@ proc ::archer::xmin::exercise_arb_editor_fields {
|
||||
|
||||
set storage_attribute [arb_storage_attribute $primitive $logical_vertex]
|
||||
set actual [lindex [$ged get $geometry_name $storage_attribute] $component_index]
|
||||
::xmin::test::require {
|
||||
[::xmin::test::equivalent_values $actual $requested]
|
||||
::gui::test::require {
|
||||
[::gui::test::equivalent_values $actual $requested]
|
||||
} "$primitive $component_name wrote $actual instead of $requested to $storage_attribute"
|
||||
require_arb_standard_storage $ged $geometry_name $primitive
|
||||
|
||||
@@ -228,8 +229,8 @@ proc ::archer::xmin::exercise_editor_update {
|
||||
set original [$ged get $geometry_name]
|
||||
$object updateGeometry
|
||||
set updated [$ged get $geometry_name]
|
||||
::xmin::test::require \
|
||||
[::xmin::test::equivalent_values $updated $original] \
|
||||
::gui::test::require \
|
||||
[::gui::test::equivalent_values $updated $original] \
|
||||
"$class changed geometry during an unmodified update: original={$original}, updated={$updated}"
|
||||
if {[regexp {^Arb([4-8])EditFrame$} $class unused arb_type]} {
|
||||
exercise_arb_editor_fields $object $ged $geometry_name \
|
||||
@@ -308,29 +309,29 @@ proc ::archer::xmin::exercise_wizard_build {
|
||||
error "$class geometry generation failed: $result"
|
||||
}
|
||||
|
||||
::xmin::test::require {$result eq $top} "$class returned '$result' instead of its top object '$top'"
|
||||
::xmin::test::require {[$ged exists $top]} "$class did not create its top database object '$top'"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {$result eq $top} "$class returned '$result' instead of its top object '$top'"
|
||||
::gui::test::require {[$ged exists $top]} "$class did not create its top database object '$top'"
|
||||
::gui::test::require {
|
||||
[$ged attr get $top WizardClass] eq $class
|
||||
} "$class did not identify its generated database object"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength [$object getWizardState]] > 0
|
||||
} "$class did not retain its generation parameters"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lsearch -exact [$ged who] $top] >= 0
|
||||
} "$class did not draw its generated database object"
|
||||
if {$class eq "TankWizard"} {
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$ged exists ${top}_gun_tube.r]
|
||||
} "TankWizard omitted its transformed gun-barrel region"
|
||||
set xml [$object buildTankXML]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string first "<Name>$top</Name>" $xml] >= 0 &&
|
||||
[string first "<Name>Gun Barrel</Name>" $xml] >= 0
|
||||
} "TankWizard XML omitted its top system or gun component"
|
||||
set open_systems [llength [regexp -all -inline {<System>} $xml]]
|
||||
set close_systems [llength [regexp -all -inline {</System>} $xml]]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
$open_systems > 10 && $open_systems == $close_systems
|
||||
} "TankWizard XML has unbalanced system elements"
|
||||
}
|
||||
@@ -385,22 +386,22 @@ proc ::archer::xmin::exercise_attribute_groups_utility {application} {
|
||||
AttrGroupsDisplayUtilityP $object $application
|
||||
update
|
||||
set group_list [$object component glist]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$group_list get 0 end] eq "Xmin"
|
||||
} "attribute-groups utility did not load its database definition"
|
||||
$group_list selection set 0
|
||||
uplevel #0 [$group_list cget -selectioncommand]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$object getCurrentGroup] eq "Xmin"
|
||||
} "attribute-groups utility did not select its group"
|
||||
|
||||
set attribute_list [$object component alist]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$attribute_list get 0 end] eq "alpha beta"
|
||||
} "attribute-groups utility did not load the grouped values"
|
||||
$attribute_list selection set 0
|
||||
set highlighted [$object highlightSelectedAttr]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lsearch -exact [lindex $highlighted 0] xmin-attr-alpha.s] >= 0
|
||||
} "attribute-groups utility did not resolve and highlight the selected value"
|
||||
::itcl::delete object $object
|
||||
@@ -416,7 +417,7 @@ proc ::archer::xmin::exercise_lod_utility {application} {
|
||||
update
|
||||
|
||||
set dialog "$object.lodDialog"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength [info commands $dialog]] == 1 && [winfo exists $dialog]
|
||||
} "LOD utility did not create its configuration dialog"
|
||||
set frame "$dialog.lodFrame"
|
||||
@@ -428,7 +429,7 @@ proc ::archer::xmin::exercise_lod_utility {application} {
|
||||
update
|
||||
set updated_points [$ged lod scale points]
|
||||
set updated_curves [$ged lod scale curves]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
abs($updated_points - 0.7) < 1.0e-9 &&
|
||||
abs($updated_curves - 9.0) < 1.0e-9
|
||||
} "LOD utility controls set points=$updated_points and curves=$updated_curves"
|
||||
@@ -457,7 +458,7 @@ proc ::archer::xmin::exercise_bot_utility {application} {
|
||||
BotUtilityP $object $application
|
||||
update
|
||||
set selector [$object component combo]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lsearch -exact [$selector cget -values] $bot] >= 0
|
||||
} "BoT utility did not list its available mesh"
|
||||
$object configure -selectedbot $bot
|
||||
@@ -471,7 +472,7 @@ proc ::archer::xmin::exercise_bot_utility {application} {
|
||||
lappend editors $editor
|
||||
}
|
||||
}
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength $editors] == 1 && [$ged exists "$bot.edit"]
|
||||
} "BoT utility did not launch an Archer-backed editor with a working copy"
|
||||
set editor [lindex $editors 0]
|
||||
@@ -507,11 +508,11 @@ proc ::archer::xmin::exercise_combination_edit {application} {
|
||||
set combination [lrange [$ged get xmin-tree.c] 1 end]
|
||||
set original_tree [bu_get_value_by_keyword tree $combination]
|
||||
set flattened_tree [ArcherCore::unpackTree $original_tree]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[ArcherCore::packTree $flattened_tree] ne $original_tree
|
||||
} "Archer combination fixture does not exercise a lossy tree grouping"
|
||||
set spaced_leaf [list l [lindex $members 1]]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[ArcherCore::packTree [ArcherCore::unpackTree $spaced_leaf]] eq $spaced_leaf
|
||||
} "Archer tree editor did not preserve a member name containing spaces"
|
||||
|
||||
@@ -527,9 +528,9 @@ proc ::archer::xmin::exercise_combination_edit {application} {
|
||||
set updated [lrange [$ged get xmin-tree.c] 1 end]
|
||||
set updated_tree [bu_get_value_by_keyword tree $updated]
|
||||
set updated_rgb [bu_get_value_by_keyword rgb $updated]
|
||||
::xmin::test::require {$updated_tree eq $original_tree} \
|
||||
::gui::test::require {$updated_tree eq $original_tree} \
|
||||
"editing a combination attribute changed its Boolean tree"
|
||||
::xmin::test::require {$updated_rgb eq "17 34 51"} \
|
||||
::gui::test::require {$updated_rgb eq "17 34 51"} \
|
||||
"Archer did not apply the requested combination color"
|
||||
::itcl::delete object $editor
|
||||
exercise_object_lifecycle CombEditFrame $editor \
|
||||
@@ -547,7 +548,7 @@ proc ::archer::xmin::exercise_combination_edit {application} {
|
||||
break
|
||||
}
|
||||
}
|
||||
::xmin::test::require {$combination_node ne ""} \
|
||||
::gui::test::require {$combination_node ne ""} \
|
||||
"Archer hierarchy omitted the test combination"
|
||||
$tree focus $combination_node
|
||||
$tree item $combination_node -open true
|
||||
@@ -557,7 +558,7 @@ proc ::archer::xmin::exercise_combination_edit {application} {
|
||||
foreach child [$tree children $combination_node] {
|
||||
lappend child_names [$tree item $child -text]
|
||||
}
|
||||
::xmin::test::require {[lsort $child_names] eq [lsort $members]} \
|
||||
::gui::test::require {[lsort $child_names] eq [lsort $members]} \
|
||||
"Archer hierarchy reported the wrong combination members: $child_names"
|
||||
}
|
||||
|
||||
@@ -586,7 +587,7 @@ proc ::archer::xmin::exercise_raytrace_abort {application} {
|
||||
set raytrace_button [$toolbar component raytrace]
|
||||
set launch_command [$toolbar itemcget raytrace -command]
|
||||
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string first raytracePlus $launch_command] >= 0
|
||||
} "Archer raytrace toolbar button does not start a raytrace"
|
||||
|
||||
@@ -597,14 +598,14 @@ proc ::archer::xmin::exercise_raytrace_abort {application} {
|
||||
$raytrace_button invoke
|
||||
|
||||
set abort_command [$toolbar itemcget raytrace -command]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
$abort_command ne $launch_command &&
|
||||
[string first abort $abort_command] >= 0
|
||||
} "Archer did not turn its raytrace toolbar button into Abort"
|
||||
|
||||
$raytrace_button invoke
|
||||
wait_for {$raytrace_aborted ne ""} "RtWizard abort callback"
|
||||
::xmin::test::require {$raytrace_aborted} \
|
||||
::gui::test::require {$raytrace_aborted} \
|
||||
"Archer reported normal completion after the Abort action"
|
||||
wait_for {
|
||||
[string first raytracePlus [$toolbar itemcget raytrace -command]] >= 0
|
||||
@@ -614,22 +615,22 @@ proc ::archer::xmin::exercise_raytrace_abort {application} {
|
||||
proc ::archer::xmin::run {} {
|
||||
variable application
|
||||
set application $::ArcherCore::application
|
||||
::xmin::test::require {[llength [info commands $application]] == 1} \
|
||||
::gui::test::require {[llength [info commands $application]] == 1} \
|
||||
"Archer application object was not created"
|
||||
::xmin::test::require {[winfo ismapped $application]} \
|
||||
::gui::test::require {[winfo ismapped $application]} \
|
||||
"Archer main window is not mapped"
|
||||
::xmin::test::require {[string match {Archer *} [wm title $application]]} \
|
||||
::gui::test::require {[string match {Archer *} [wm title $application]]} \
|
||||
"unexpected Archer main-window title"
|
||||
|
||||
set opened_database [$application WhatsOpen]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[file normalize $opened_database] eq [file normalize $::env(ARCHER_WORK_DATABASE)]
|
||||
} "Archer did not open the relative database argument"
|
||||
|
||||
set widget_inventory [::xmin::test::widget_inventory $application]
|
||||
set menu_inventory [::xmin::test::menu_inventory $application]
|
||||
::xmin::test::write widget_inventory $widget_inventory
|
||||
::xmin::test::write menu_inventory $menu_inventory
|
||||
set widget_inventory [::gui::test::widget_inventory $application]
|
||||
set menu_inventory [::gui::test::menu_inventory $application]
|
||||
::gui::test::write widget_inventory $widget_inventory
|
||||
::gui::test::write menu_inventory $menu_inventory
|
||||
compare_manifest $menu_inventory
|
||||
|
||||
foreach labels {
|
||||
@@ -641,27 +642,27 @@ proc ::archer::xmin::run {} {
|
||||
{Help {Archer Help...}}
|
||||
{Help {About Archer...}}
|
||||
} {
|
||||
::xmin::test::require {
|
||||
[::xmin::test::find_menu_entry $application $labels] ne ""
|
||||
::gui::test::require {
|
||||
[::gui::test::find_menu_entry $application $labels] ne ""
|
||||
} "missing Archer menu entry: [join $labels { > }]"
|
||||
}
|
||||
|
||||
$application draw all.g
|
||||
update
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lsearch -exact [$application gedCmd who] all.g] >= 0
|
||||
} "Archer did not draw all.g"
|
||||
|
||||
::xmin::test::invoke_menu_entry $application \
|
||||
::gui::test::invoke_menu_entry $application \
|
||||
{Display {Standard Views} Front}
|
||||
set aet [$application gedCmd aet]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
abs([lindex $aet 0]) < 0.001 && abs([lindex $aet 1]) < 0.001
|
||||
} "Front menu entry did not set the expected view: $aet"
|
||||
|
||||
::xmin::test::invoke_menu_entry $application \
|
||||
::gui::test::invoke_menu_entry $application \
|
||||
{Display {Background Color} Black}
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$application gedCmd bg] eq "0 0 0"
|
||||
} "Black background menu entry did not update the display"
|
||||
|
||||
@@ -672,7 +673,7 @@ proc ::archer::xmin::run {} {
|
||||
exercise_dialog $application {Help {About Archer...}} {About Archer}
|
||||
|
||||
exercise_combination_edit $application
|
||||
::xmin::test::exercise_sketch_segments SketchCArc SketchBezier Archer ::archer::xmin
|
||||
::gui::test::exercise_sketch_segments SketchCArc SketchBezier Archer ::archer::xmin
|
||||
exercise_wizard_builds $application
|
||||
exercise_editor_lifecycles $application
|
||||
exercise_plugin_lifecycles $application
|
||||
@@ -692,10 +693,10 @@ proc ::archer::xmin::run_checked {} {
|
||||
}
|
||||
}
|
||||
|
||||
set work_database [file join $::env(XMIN_TEST_DIR) archer-relative.g]
|
||||
set work_database [file join $::env(GUI_TEST_DIR) archer-relative.g]
|
||||
file copy -force $::env(ARCHER_TEST_DATABASE) $work_database
|
||||
set ::env(ARCHER_WORK_DATABASE) $work_database
|
||||
cd $::env(XMIN_TEST_DIR)
|
||||
cd $::env(GUI_TEST_DIR)
|
||||
set argv [list [file tail $work_database]]
|
||||
set argc 1
|
||||
set argv0 [info nameofexecutable]
|
||||
@@ -707,7 +708,7 @@ if {[catch {source $::env(ARCHER_LAUNCH)} message options]} {
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
::xmin::test::capture_background_errors
|
||||
::gui::test::capture_background_errors
|
||||
|
||||
# Let the splash timer finish so it cannot obscure dialog discovery.
|
||||
after 1800 ::archer::xmin::run_checked
|
||||
|
||||
@@ -41,7 +41,7 @@ quadratic display-list or scene-object scans.
|
||||
The focused `regress-mged-xmin-gui-controls` fixture drives ViewRing, grid,
|
||||
ADC, font persistence, and About through their live Tk widgets and checks the
|
||||
resulting MGED state, view, named font, or generated preferences file. It also
|
||||
requires Itcl 3.4, Itk 3.4, and Iwidgets 4.1.1 from the running
|
||||
requires Itcl 4.3.0, Itk 4.2.3, and Iwidgets 4.1.1 from the running
|
||||
application. This complements the deeper multi-display-manager fixture with
|
||||
fast coverage for stateful controls that are otherwise easy to inventory
|
||||
without actually validating. The semantic MGED fixtures share the Xmin
|
||||
|
||||
+231
-264
@@ -17,25 +17,16 @@ MIN_RENDER_CHANGED_CHANNELS=100
|
||||
MIN_REFERENCE_EXACT_PERCENT=90
|
||||
MAX_RAYTRACE_ELAPSED_MS=5000
|
||||
RGB_CHANNELS=3
|
||||
SCREEN_GEOMETRY=1280x960x24
|
||||
SCREEN_WIDTH=${SCREEN_GEOMETRY%%x*}
|
||||
screen_height_depth=${SCREEN_GEOMETRY#*x}
|
||||
SCREEN_HEIGHT=${screen_height_depth%%x*}
|
||||
COMMAND_GEOMETRY=680x520+0+0
|
||||
GRAPHICS_GEOMETRY=512x512+700+0
|
||||
MGED_TEST_SHELL=${MGED_TEST_SHELL:-sh}
|
||||
: "${GUI_TEST_SHELL:?GUI_TEST_SHELL is required}"
|
||||
. "$GUI_TEST_SHELL"
|
||||
GUI_STABLE_QUIET_MS=$STABLE_QUIET
|
||||
GUI_STABLE_TIMEOUT_MS=$STABLE_TIMEOUT
|
||||
TOP_LEVEL_MENUS="file:File edit:Edit create:Create view:View viewring:ViewRing settings:Settings modes:Modes misc:Misc tools:Tools help:Help"
|
||||
MGED_DM_TYPES=${MGED_DM_TYPES:-tkswrast}
|
||||
MGED_GUI_APNG_DIR=${MGED_GUI_APNG_DIR:-.}
|
||||
MGED_PIPE_ORACLE=${MGED_PIPE_ORACLE:-${MGED_XMIN_RC%/*}/xmin_gui_pipe_oracle.tcl}
|
||||
|
||||
require_executable()
|
||||
{
|
||||
if [ ! -x "$1" ]; then
|
||||
echo "FAIL: required executable is unavailable: $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
MGED_PIPE_ORACLE=${MGED_PIPE_ORACLE:-${MGED_GUI_RC%/*}/xmin_gui_pipe_oracle.tcl}
|
||||
|
||||
wait_for_file()
|
||||
{
|
||||
@@ -51,7 +42,7 @@ wait_for_file_with_limit()
|
||||
if [ -s "$path" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ -s "$MGED_XMIN_TEST_DIR/result" ]; then
|
||||
if [ -s "$MGED_GUI_TEST_DIR/result" ]; then
|
||||
return 1
|
||||
fi
|
||||
if [ -n "${MGED_PID:-}" ] && ! kill -0 "$MGED_PID" 2>/dev/null; then
|
||||
@@ -70,7 +61,7 @@ wait_for_value()
|
||||
if [ -f "$1" ] && [ "$(sed -n '1p' "$1")" = "$2" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ -s "$MGED_XMIN_TEST_DIR/result" ]; then
|
||||
if [ -s "$MGED_GUI_TEST_DIR/result" ]; then
|
||||
return 1
|
||||
fi
|
||||
sleep "$WAIT_DELAY"
|
||||
@@ -86,7 +77,7 @@ wait_for_not_value()
|
||||
if [ -s "$1" ] && [ "$(sed -n '1p' "$1")" != "$2" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ -s "$MGED_XMIN_TEST_DIR/result" ]; then
|
||||
if [ -s "$MGED_GUI_TEST_DIR/result" ]; then
|
||||
return 1
|
||||
fi
|
||||
sleep "$WAIT_DELAY"
|
||||
@@ -100,17 +91,17 @@ start_raytrace()
|
||||
# xminctl can return before Tk handles the click. Wait for the button
|
||||
# callback before enabling the monitor's MGED command polling.
|
||||
click_target raytrace_button
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/raytrace_invocations" "$1"; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/raytrace_invocations" "$1"; then
|
||||
fail "Raytrace Control Panel did not process button click $1"
|
||||
fi
|
||||
printf '%s\n' "$1" > "$MGED_XMIN_TEST_DIR/raytrace_request"
|
||||
printf '%s\n' "$1" > "$MGED_GUI_TEST_DIR/raytrace_request"
|
||||
}
|
||||
|
||||
query_database()
|
||||
{
|
||||
database=$1
|
||||
query=$2
|
||||
error_file="$MGED_XMIN_TEST_DIR/database_query_error"
|
||||
error_file="$MGED_GUI_TEST_DIR/database_query_error"
|
||||
count=0
|
||||
while [ "$count" -lt "$DATABASE_QUERY_LIMIT" ]; do
|
||||
if DATABASE_VALUE=$("$MGED_BIN" -c "$database" "$query" 2>"$error_file"); then
|
||||
@@ -137,24 +128,24 @@ read_point()
|
||||
|
||||
read_target()
|
||||
{
|
||||
TARGET_WINDOW=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/$1_window")
|
||||
read_point "$MGED_XMIN_TEST_DIR/$1"
|
||||
TARGET_WINDOW=$(sed -n '1p' "$MGED_GUI_TEST_DIR/$1_window")
|
||||
read_point "$MGED_GUI_TEST_DIR/$1"
|
||||
}
|
||||
|
||||
click_target()
|
||||
{
|
||||
read_target "$1"
|
||||
"$XMIN_CTL" click --delay "$CLICK_DELAY" "$TARGET_WINDOW" "$POINT_X" "$POINT_Y" "${2:-1}"
|
||||
"$GUI_TEST_CTL" click --delay "$CLICK_DELAY" "$TARGET_WINDOW" "$POINT_X" "$POINT_Y" "${2:-1}"
|
||||
}
|
||||
|
||||
activate_menu_target()
|
||||
{
|
||||
read_target "$1"
|
||||
"$XMIN_CTL" mouse-move "$TARGET_WINDOW" "$POINT_X" "$POINT_Y"
|
||||
"$XMIN_CTL" wait-stable --quiet "$STABLE_QUIET" \
|
||||
"$GUI_TEST_CTL" mouse-move "$TARGET_WINDOW" "$POINT_X" "$POINT_Y"
|
||||
"$GUI_TEST_CTL" wait-stable --quiet "$STABLE_QUIET" \
|
||||
--timeout "$STABLE_TIMEOUT" root >/dev/null 2>&1 || true
|
||||
"$XMIN_CTL" button 1 down
|
||||
"$XMIN_CTL" button 1 up
|
||||
"$GUI_TEST_CTL" button 1 down
|
||||
"$GUI_TEST_CTL" button 1 up
|
||||
}
|
||||
|
||||
replace_entry_text()
|
||||
@@ -165,14 +156,14 @@ replace_entry_text()
|
||||
expected_value=$4
|
||||
|
||||
click_target "$target"
|
||||
"$XMIN_CTL" key end
|
||||
"$GUI_TEST_CTL" key end
|
||||
remaining=${#initial_value}
|
||||
while [ "$remaining" -gt 0 ]; do
|
||||
"$XMIN_CTL" key backspace
|
||||
"$GUI_TEST_CTL" key backspace
|
||||
remaining=$((remaining - 1))
|
||||
done
|
||||
wait_for_value "$current_file" "" || return 1
|
||||
"$XMIN_CTL" type "$expected_value"
|
||||
"$GUI_TEST_CTL" type "$expected_value"
|
||||
wait_for_value "$current_file" "$expected_value"
|
||||
}
|
||||
|
||||
@@ -183,8 +174,8 @@ capture_failure()
|
||||
|
||||
capture_frame()
|
||||
{
|
||||
frames_dir="$MGED_XMIN_RUN_DIR/frames"
|
||||
counter_file="$MGED_XMIN_RUN_DIR/frame_counter"
|
||||
frames_dir="$MGED_GUI_RUN_DIR/frames"
|
||||
counter_file="$MGED_GUI_RUN_DIR/frame_counter"
|
||||
"$CMAKE_COMMAND" -E make_directory "$frames_dir"
|
||||
|
||||
frame_number=0
|
||||
@@ -194,14 +185,14 @@ capture_frame()
|
||||
frame_number=$((frame_number + 1))
|
||||
frame_name=$(printf '%06d.ppm' "$frame_number")
|
||||
|
||||
"$XMIN_CTL" wait-stable --quiet "$STABLE_QUIET" \
|
||||
"$GUI_TEST_CTL" wait-stable --quiet "$STABLE_QUIET" \
|
||||
--timeout "$STABLE_TIMEOUT" root >/dev/null 2>&1 || true
|
||||
if ! "$XMIN_CTL" capture-root "$frames_dir/$frame_name" >/dev/null 2>&1; then
|
||||
if ! "$GUI_TEST_CTL" capture-screen "$frames_dir/$frame_name" >/dev/null 2>&1; then
|
||||
return 1
|
||||
fi
|
||||
printf '%s\n' "$frame_number" > "$counter_file"
|
||||
printf '%06d %s %s\n' "$frame_number" "$MGED_DM_TYPE" "$1" \
|
||||
>> "$MGED_XMIN_RUN_DIR/frames.log"
|
||||
>> "$MGED_GUI_RUN_DIR/frames.log"
|
||||
}
|
||||
|
||||
record_state()
|
||||
@@ -213,29 +204,13 @@ record_state()
|
||||
|
||||
capture_dm_snapshot()
|
||||
{
|
||||
snapshot="$MGED_XMIN_TEST_DIR/$1.ppm"
|
||||
root_snapshot="$MGED_XMIN_TEST_DIR/$1-root.ppm"
|
||||
root_pixels="$MGED_XMIN_TEST_DIR/$1-root.pix"
|
||||
cropped_pixels="$MGED_XMIN_TEST_DIR/$1-cropped.pix"
|
||||
snapshot="$MGED_GUI_TEST_DIR/$1.ppm"
|
||||
read -r dm_x dm_y dm_width dm_height \
|
||||
< "$MGED_XMIN_TEST_DIR/active_dm_geometry"
|
||||
lower_y=$((SCREEN_HEIGHT - dm_y - dm_height))
|
||||
upper_y=$((lower_y + dm_height - 1))
|
||||
right_x=$((dm_x + dm_width - 1))
|
||||
|
||||
"$XMIN_CTL" wait-stable --quiet "$STABLE_QUIET" \
|
||||
--timeout "$STABLE_TIMEOUT" root >/dev/null 2>&1 || true
|
||||
if ! "$XMIN_CTL" capture-root "$root_snapshot" >/dev/null 2>&1 ||
|
||||
! "$ICV_BIN" "$root_snapshot" "$root_pixels" >/dev/null 2>&1 ||
|
||||
! "$PIXCROP_BIN" "$root_pixels" "$cropped_pixels" \
|
||||
"$SCREEN_WIDTH" "$dm_width" "$dm_height" \
|
||||
"$dm_x" "$upper_y" "$right_x" "$upper_y" \
|
||||
"$right_x" "$lower_y" "$dm_x" "$lower_y" >/dev/null 2>&1 ||
|
||||
! "$ICV_BIN" -w "$dm_width" -n "$dm_height" \
|
||||
"$cropped_pixels" "$snapshot" >/dev/null 2>&1; then
|
||||
< "$MGED_GUI_TEST_DIR/active_dm_geometry"
|
||||
if ! gui_capture_region "$snapshot" "$dm_x" "$dm_y" \
|
||||
"$dm_width" "$dm_height"; then
|
||||
fail "could not capture display-manager snapshot '$1'"
|
||||
fi
|
||||
"$CMAKE_COMMAND" -E rm -f "$root_snapshot" "$root_pixels" "$cropped_pixels"
|
||||
}
|
||||
|
||||
assert_raw_images_equal()
|
||||
@@ -315,7 +290,7 @@ wait_for_changed_dm_snapshot()
|
||||
description=$1
|
||||
baseline=$2
|
||||
snapshot_name=$3
|
||||
snapshot="$MGED_XMIN_TEST_DIR/$snapshot_name.ppm"
|
||||
snapshot="$MGED_GUI_TEST_DIR/$snapshot_name.ppm"
|
||||
count=0
|
||||
changed_channels=0
|
||||
|
||||
@@ -341,7 +316,7 @@ assert_raytrace_duration()
|
||||
{
|
||||
request=$1
|
||||
description=$2
|
||||
elapsed_file="$MGED_XMIN_TEST_DIR/raytrace_elapsed_${request}_ms"
|
||||
elapsed_file="$MGED_GUI_TEST_DIR/raytrace_elapsed_${request}_ms"
|
||||
if ! wait_for_file "$elapsed_file"; then
|
||||
fail "$description did not report its elapsed time"
|
||||
fi
|
||||
@@ -358,8 +333,8 @@ assert_raytrace_duration()
|
||||
toggle_renderer_setting()
|
||||
{
|
||||
setting=$1
|
||||
initial=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/renderer_${setting}_initial")
|
||||
mutable=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/renderer_${setting}_mutable")
|
||||
initial=$(sed -n '1p' "$MGED_GUI_TEST_DIR/renderer_${setting}_initial")
|
||||
mutable=$(sed -n '1p' "$MGED_GUI_TEST_DIR/renderer_${setting}_mutable")
|
||||
if [ "$initial" -eq 0 ]; then
|
||||
expected=1
|
||||
else
|
||||
@@ -367,13 +342,13 @@ toggle_renderer_setting()
|
||||
fi
|
||||
|
||||
click_target main_misc_menu
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/renderer_${setting}" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/renderer_${setting}_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/renderer_${setting}" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/renderer_${setting}_window"; then
|
||||
fail "Misc menu did not expose $setting"
|
||||
fi
|
||||
record_state "Misc menu $setting"
|
||||
activate_menu_target "renderer_${setting}"
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/renderer_${setting}_gui_current" "$expected"; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/renderer_${setting}_gui_current" "$expected"; then
|
||||
fail "$setting menu state did not change to $expected"
|
||||
fi
|
||||
backend_expected=$expected
|
||||
@@ -382,7 +357,7 @@ toggle_renderer_setting()
|
||||
backend_expected=$initial
|
||||
state_description="requested state $expected (backend unavailable)"
|
||||
fi
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/renderer_${setting}_current" \
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/renderer_${setting}_current" \
|
||||
"$backend_expected"; then
|
||||
fail "$setting backend state did not become $backend_expected"
|
||||
fi
|
||||
@@ -391,17 +366,17 @@ toggle_renderer_setting()
|
||||
click_target main_misc_menu
|
||||
record_state "Misc menu $setting restore"
|
||||
activate_menu_target "renderer_${setting}"
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/renderer_${setting}_gui_current" "$initial"; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/renderer_${setting}_gui_current" "$initial"; then
|
||||
fail "$setting menu state did not return to $initial"
|
||||
fi
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/renderer_${setting}_current" "$initial"; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/renderer_${setting}_current" "$initial"; then
|
||||
fail "$setting did not return to $initial"
|
||||
fi
|
||||
}
|
||||
|
||||
create_recording()
|
||||
{
|
||||
frames_dir="$MGED_XMIN_RUN_DIR/frames"
|
||||
frames_dir="$MGED_GUI_RUN_DIR/frames"
|
||||
set -- "$frames_dir"/*.ppm
|
||||
if [ ! -f "$1" ]; then
|
||||
echo "FAIL: MGED GUI run did not produce recording frames" >&2
|
||||
@@ -417,14 +392,14 @@ create_recording()
|
||||
return 1
|
||||
fi
|
||||
|
||||
validation_dir="$MGED_XMIN_RUN_DIR/apng_validation"
|
||||
validation_dir="$MGED_GUI_RUN_DIR/apng_validation"
|
||||
"$CMAKE_COMMAND" -E make_directory "$validation_dir"
|
||||
if ! "$ICV_BIN" anim extract "$apng" "$validation_dir/frame_" \
|
||||
>/dev/null 2>&1; then
|
||||
echo "FAIL: could not reopen MGED GUI recording $apng" >&2
|
||||
return 1
|
||||
fi
|
||||
expected_frames=$(sed -n '1p' "$MGED_XMIN_RUN_DIR/frame_counter")
|
||||
expected_frames=$(sed -n '1p' "$MGED_GUI_RUN_DIR/frame_counter")
|
||||
actual_frames=$(find "$validation_dir" -type f -name '*.png' | wc -l | tr -d ' ')
|
||||
if [ "$actual_frames" -ne "$expected_frames" ]; then
|
||||
echo "FAIL: APNG has $actual_frames frames; expected $expected_frames" >&2
|
||||
@@ -448,32 +423,28 @@ fail()
|
||||
MGED_PID=""
|
||||
echo "MGED exited with status $mged_status" >&2
|
||||
fi
|
||||
if [ -f "$MGED_XMIN_TEST_DIR/result" ]; then
|
||||
sed -n '1,20p' "$MGED_XMIN_TEST_DIR/result" >&2
|
||||
if [ -f "$MGED_GUI_TEST_DIR/result" ]; then
|
||||
sed -n '1,20p' "$MGED_GUI_TEST_DIR/result" >&2
|
||||
fi
|
||||
for diagnostic in "$MGED_XMIN_TEST_DIR"/*_debug; do
|
||||
for diagnostic in "$MGED_GUI_TEST_DIR"/*_debug; do
|
||||
if [ -f "$diagnostic" ]; then
|
||||
echo "$(basename "$diagnostic"): $(sed -n '1,20p' "$diagnostic")" >&2
|
||||
fi
|
||||
done
|
||||
if [ -f "$MGED_XMIN_TEST_DIR/mged.log" ]; then
|
||||
if [ -f "$MGED_GUI_TEST_DIR/mged.log" ]; then
|
||||
echo "MGED log follows:" >&2
|
||||
sed -n '1,240p' "$MGED_XMIN_TEST_DIR/mged.log" >&2
|
||||
sed -n '1,240p' "$MGED_GUI_TEST_DIR/mged.log" >&2
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "${MGED_XMIN_INNER:-0}" -eq 0 ]; then
|
||||
require_executable "$MGED_BIN"
|
||||
require_executable "$XMIN_CTL"
|
||||
if [ "${MGED_XMIN_ACTIVE_SESSION:-0}" -eq 0 ]; then
|
||||
require_executable "$XMIN_RUN"
|
||||
require_executable "$XMIN_SERVER"
|
||||
fi
|
||||
require_executable "$ICV_BIN"
|
||||
require_executable "$PIXCROP_BIN"
|
||||
if [ ! -f "$MGED_XMIN_RC" ]; then
|
||||
echo "FAIL: MGED Xmin rc file is unavailable: $MGED_XMIN_RC" >&2
|
||||
if [ "${MGED_GUI_INNER:-0}" -eq 0 ]; then
|
||||
gui_require_executable "$MGED_BIN"
|
||||
gui_require_executable "$GUI_TEST_CTL"
|
||||
gui_require_executable "$ICV_BIN"
|
||||
gui_require_executable "$PIXCROP_BIN"
|
||||
if [ ! -f "$MGED_GUI_RC" ]; then
|
||||
echo "FAIL: MGED GUI rc file is unavailable: $MGED_GUI_RC" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$MGED_PIPE_ORACLE" ]; then
|
||||
@@ -481,40 +452,36 @@ if [ "${MGED_XMIN_INNER:-0}" -eq 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MGED_XMIN_RUN_DIR=$(mktemp -d /tmp/mged-xmin-gui.XXXXXX)
|
||||
export MGED_XMIN_RUN_DIR
|
||||
MGED_GUI_RUN_DIR=$(mktemp -d "${TMPDIR:-/tmp}/mged-gui.XXXXXX")
|
||||
export MGED_GUI_RUN_DIR
|
||||
run_status=0
|
||||
cleanup()
|
||||
{
|
||||
if [ -n "${MGED_PID:-}" ]; then
|
||||
kill "$MGED_PID" >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [ "${MGED_XMIN_KEEP:-0}" -eq 1 ]; then
|
||||
echo "MGED Xmin test artifacts: $MGED_XMIN_RUN_DIR" >&2
|
||||
if [ "${MGED_GUI_KEEP:-0}" -eq 1 ]; then
|
||||
echo "MGED GUI test artifacts: $MGED_GUI_RUN_DIR" >&2
|
||||
else
|
||||
"$CMAKE_COMMAND" -E remove_directory "$MGED_XMIN_RUN_DIR"
|
||||
"$CMAKE_COMMAND" -E remove_directory "$MGED_GUI_RUN_DIR"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
MGED_XMIN_INNER=1
|
||||
export MGED_XMIN_INNER
|
||||
MGED_GUI_INNER=1
|
||||
export MGED_GUI_INNER
|
||||
for MGED_DM_TYPE in $MGED_DM_TYPES; do
|
||||
export MGED_DM_TYPE
|
||||
MGED_XMIN_TEST_DIR="$MGED_XMIN_RUN_DIR/cases/$MGED_DM_TYPE"
|
||||
export MGED_XMIN_TEST_DIR
|
||||
"$CMAKE_COMMAND" -E make_directory "$MGED_XMIN_TEST_DIR"
|
||||
XMIN_TEST_DIR=$MGED_XMIN_TEST_DIR
|
||||
export XMIN_TEST_DIR
|
||||
test_db="$MGED_XMIN_TEST_DIR/gui-edit.g"
|
||||
MGED_GUI_TEST_DIR="$MGED_GUI_RUN_DIR/cases/$MGED_DM_TYPE"
|
||||
export MGED_GUI_TEST_DIR
|
||||
"$CMAKE_COMMAND" -E make_directory "$MGED_GUI_TEST_DIR"
|
||||
GUI_TEST_DIR=$MGED_GUI_TEST_DIR
|
||||
export GUI_TEST_DIR
|
||||
test_db="$MGED_GUI_TEST_DIR/gui-edit.g"
|
||||
"$MGED_BIN" -c "$test_db" "in gui.s sph 0 0 0 10" \
|
||||
>"$MGED_XMIN_TEST_DIR/create.log" 2>&1
|
||||
>"$MGED_GUI_TEST_DIR/create.log" 2>&1
|
||||
set +e
|
||||
if [ "${MGED_XMIN_ACTIVE_SESSION:-0}" -eq 1 ]; then
|
||||
"$MGED_TEST_SHELL" "$0"
|
||||
else
|
||||
"$XMIN_RUN" --server "$XMIN_SERVER" --screen "$SCREEN_GEOMETRY" -- "$0"
|
||||
fi
|
||||
sh "$0"
|
||||
dm_status=$?
|
||||
set -e
|
||||
if [ "$dm_status" -ne 0 ]; then
|
||||
@@ -528,7 +495,7 @@ if [ "${MGED_XMIN_INNER:-0}" -eq 0 ]; then
|
||||
fi
|
||||
if [ "$sphere_vertex" != "5 0 0" ]; then
|
||||
echo "FAIL: $MGED_DM_TYPE primitive edit stored V {$sphere_vertex}, expected {5 0 0}" >&2
|
||||
sed -n '1,20p' "$MGED_XMIN_TEST_DIR/database_query_error" >&2
|
||||
sed -n '1,20p' "$MGED_GUI_TEST_DIR/database_query_error" >&2
|
||||
run_status=1
|
||||
break
|
||||
fi
|
||||
@@ -540,7 +507,7 @@ if [ "${MGED_XMIN_INNER:-0}" -eq 0 ]; then
|
||||
run_status=1
|
||||
break
|
||||
fi
|
||||
read -r matrix_x matrix_y < "$MGED_XMIN_TEST_DIR/matrix_expected"
|
||||
read -r matrix_x matrix_y < "$MGED_GUI_TEST_DIR/matrix_expected"
|
||||
if query_database "$test_db" "get matrix.c tree"; then
|
||||
matrix_tree=$DATABASE_VALUE
|
||||
else
|
||||
@@ -559,13 +526,13 @@ if [ "${MGED_XMIN_INNER:-0}" -eq 0 ]; then
|
||||
recording_status=$?
|
||||
set -e
|
||||
if [ "$run_status" -ne 0 ] || [ "$recording_status" -ne 0 ]; then
|
||||
MGED_XMIN_KEEP=1
|
||||
MGED_GUI_KEEP=1
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
test_db="$MGED_XMIN_TEST_DIR/gui-edit.g"
|
||||
test_db="$MGED_GUI_TEST_DIR/gui-edit.g"
|
||||
inner_cleanup()
|
||||
{
|
||||
if [ -n "${MGED_PID:-}" ]; then
|
||||
@@ -574,213 +541,213 @@ inner_cleanup()
|
||||
}
|
||||
trap inner_cleanup EXIT INT TERM
|
||||
|
||||
"$MGED_BIN" --gui --dm-type "$MGED_DM_TYPE" --rcfile "$MGED_XMIN_RC" \
|
||||
"$MGED_BIN" --gui --dm-type "$MGED_DM_TYPE" --rcfile "$MGED_GUI_RC" \
|
||||
--geom "$COMMAND_GEOMETRY" --ggeom "$GRAPHICS_GEOMETRY" "$test_db" \
|
||||
>"$MGED_XMIN_TEST_DIR/mged.log" 2>&1 &
|
||||
>"$MGED_GUI_TEST_DIR/mged.log" 2>&1 &
|
||||
MGED_PID=$!
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/main_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/main_window"; then
|
||||
fail "MGED main window did not become ready"
|
||||
fi
|
||||
|
||||
main_window=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/main_window")
|
||||
"$XMIN_CTL" activate "$main_window"
|
||||
main_window=$(sed -n '1p' "$MGED_GUI_TEST_DIR/main_window")
|
||||
"$GUI_TEST_CTL" activate "$main_window"
|
||||
record_state "MGED ready"
|
||||
|
||||
for menu in $TOP_LEVEL_MENUS; do
|
||||
menu_name=${menu%%:*}
|
||||
menu_label=${menu#*:}
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/main_${menu_name}_menu" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/main_${menu_name}_menu_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/main_${menu_name}_menu" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/main_${menu_name}_menu_window"; then
|
||||
fail "MGED $menu_label menu target did not become ready"
|
||||
fi
|
||||
click_target "main_${menu_name}_menu"
|
||||
record_state "$menu_label menu"
|
||||
if [ "$menu_name" = misc ]; then
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/faceplate_toggle" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/faceplate_toggle_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/orig_gui_toggle" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/orig_gui_toggle_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/faceplate_toggle" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/faceplate_toggle_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/orig_gui_toggle" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/orig_gui_toggle_window"; then
|
||||
fail "Misc menu Faceplate targets did not become ready"
|
||||
fi
|
||||
fi
|
||||
"$XMIN_CTL" key escape
|
||||
"$GUI_TEST_CTL" key escape
|
||||
done
|
||||
"$XMIN_CTL" click --delay "$CLICK_DELAY" "$main_window" 100 100 1
|
||||
"$XMIN_CTL" activate "$main_window"
|
||||
"$GUI_TEST_CTL" click --delay "$CLICK_DELAY" "$main_window" 100 100 1
|
||||
"$GUI_TEST_CTL" activate "$main_window"
|
||||
|
||||
if [ "$MGED_DM_TYPE" = "tkswrast" ] && [ -n "${MGED_GUI_MANIFEST:-}" ]; then
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/menu_inventory"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/menu_inventory"; then
|
||||
fail "MGED menu inventory did not become ready"
|
||||
fi
|
||||
if ! "$CMAKE_COMMAND" -E compare_files \
|
||||
"$MGED_XMIN_TEST_DIR/menu_inventory" "$MGED_GUI_MANIFEST"; then
|
||||
"$MGED_GUI_TEST_DIR/menu_inventory" "$MGED_GUI_MANIFEST"; then
|
||||
fail "MGED menu inventory differs from $MGED_GUI_MANIFEST"
|
||||
fi
|
||||
fi
|
||||
|
||||
for setting in faceplate orig_gui; do
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/${setting}_current"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/${setting}_current"; then
|
||||
fail "MGED did not report the current $setting state"
|
||||
fi
|
||||
if [ "$(sed -n '1p' "$MGED_XMIN_TEST_DIR/${setting}_current")" -ne 1 ]; then
|
||||
if [ "$(sed -n '1p' "$MGED_GUI_TEST_DIR/${setting}_current")" -ne 1 ]; then
|
||||
click_target main_misc_menu
|
||||
record_state "Misc menu $setting"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/${setting}_toggle" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/${setting}_toggle_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/${setting}_toggle" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/${setting}_toggle_window"; then
|
||||
fail "Misc menu did not expose $setting"
|
||||
fi
|
||||
activate_menu_target "${setting}_toggle"
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/${setting}_current" 1; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/${setting}_current" 1; then
|
||||
fail "$setting did not enable the in-scene Faceplate"
|
||||
fi
|
||||
record_state "$setting enabled"
|
||||
fi
|
||||
done
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/faceplate_header" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/faceplate_header_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/faceplate_3525" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/faceplate_3525_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/faceplate_view_initial"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/faceplate_header" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/faceplate_header_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/faceplate_3525" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/faceplate_3525_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/faceplate_view_initial"; then
|
||||
fail "Faceplate targets did not become ready"
|
||||
fi
|
||||
faceplate_view_initial=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/faceplate_view_initial")
|
||||
faceplate_view_initial=$(sed -n '1p' "$MGED_GUI_TEST_DIR/faceplate_view_initial")
|
||||
click_target faceplate_header 2
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/faceplate_general_ready"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/faceplate_general_ready"; then
|
||||
fail "Faceplate general menu did not expand"
|
||||
fi
|
||||
record_state "Faceplate general menu"
|
||||
click_target faceplate_3525 2
|
||||
if ! wait_for_not_value "$MGED_XMIN_TEST_DIR/faceplate_view_current" \
|
||||
if ! wait_for_not_value "$MGED_GUI_TEST_DIR/faceplate_view_current" \
|
||||
"$faceplate_view_initial"; then
|
||||
fail "Faceplate 35,25 did not change the view"
|
||||
fi
|
||||
record_state "Faceplate 35,25 view"
|
||||
click_target faceplate_header 2
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/renderer_capabilities" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/main_misc_menu" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/main_misc_menu_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/renderer_capabilities" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/main_misc_menu" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/main_misc_menu_window"; then
|
||||
fail "renderer capability inventory did not become ready"
|
||||
fi
|
||||
renderer_capabilities=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/renderer_capabilities")
|
||||
renderer_capabilities=$(sed -n '1p' "$MGED_GUI_TEST_DIR/renderer_capabilities")
|
||||
if [ "$renderer_capabilities" != "none" ]; then
|
||||
for setting in $renderer_capabilities; do
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/renderer_${setting}_initial"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/renderer_${setting}_initial"; then
|
||||
fail "renderer did not report initial $setting state"
|
||||
fi
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/renderer_${setting}_mutable"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/renderer_${setting}_mutable"; then
|
||||
fail "renderer did not report $setting mutability"
|
||||
fi
|
||||
toggle_renderer_setting "$setting"
|
||||
done
|
||||
fi
|
||||
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/stop_general_monitors"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/renderer_monitor_stopped" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/faceplate_monitor_stopped"; then
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/stop_general_monitors"
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/renderer_monitor_stopped" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/faceplate_monitor_stopped"; then
|
||||
fail "MGED general-interface monitors did not stop"
|
||||
fi
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/main_edit_menu" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/main_edit_menu_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/main_edit_menu" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/main_edit_menu_window"; then
|
||||
fail "MGED Edit menu did not become ready"
|
||||
fi
|
||||
click_target main_edit_menu
|
||||
record_state "Edit menu"
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/primitive_editor_menu" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/primitive_editor_menu_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/primitive_editor_menu" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/primitive_editor_menu_window"; then
|
||||
fail "MGED Primitive Editor menu entry did not become ready"
|
||||
fi
|
||||
activate_menu_target primitive_editor_menu
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/editor_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/editor_window"; then
|
||||
fail "Primitive Editor did not open"
|
||||
fi
|
||||
record_state "Primitive Editor"
|
||||
|
||||
editor_window=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/editor_window")
|
||||
"$XMIN_CTL" activate "$editor_window"
|
||||
editor_window=$(sed -n '1p' "$MGED_GUI_TEST_DIR/editor_window")
|
||||
"$GUI_TEST_CTL" activate "$editor_window"
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/editor_name" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/editor_name_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/editor_name_initial" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/editor_reset" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/editor_reset_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/editor_name" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/editor_name_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/editor_name_initial" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/editor_reset" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/editor_reset_window"; then
|
||||
fail "Primitive Editor controls did not become ready"
|
||||
fi
|
||||
editor_name=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/editor_name_initial")
|
||||
editor_name=$(sed -n '1p' "$MGED_GUI_TEST_DIR/editor_name_initial")
|
||||
if ! replace_entry_text editor_name "$editor_name" \
|
||||
"$MGED_XMIN_TEST_DIR/editor_name_current" gui.s; then
|
||||
"$MGED_GUI_TEST_DIR/editor_name_current" gui.s; then
|
||||
fail "Primitive Editor name entry did not receive gui.s"
|
||||
fi
|
||||
record_state "primitive name entered"
|
||||
click_target editor_reset
|
||||
record_state "primitive load dispatched"
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/editor_loaded"
|
||||
if ! wait_for_file_with_limit "$MGED_XMIN_TEST_DIR/sphere_vx" \
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/editor_loaded"
|
||||
if ! wait_for_file_with_limit "$MGED_GUI_TEST_DIR/sphere_vx" \
|
||||
"$PRIMITIVE_LOAD_RETRY_LIMIT"; then
|
||||
click_target editor_name
|
||||
"$XMIN_CTL" key enter
|
||||
"$GUI_TEST_CTL" key enter
|
||||
record_state "primitive load keyboard retry"
|
||||
fi
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/sphere_vx" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sphere_vx_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sphere_vx_initial" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/apply_button_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/apply_button"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/sphere_vx" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sphere_vx_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sphere_vx_initial" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/apply_button_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/apply_button"; then
|
||||
fail "Primitive Editor did not load gui.s"
|
||||
fi
|
||||
|
||||
initial_value=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/sphere_vx_initial")
|
||||
initial_value=$(sed -n '1p' "$MGED_GUI_TEST_DIR/sphere_vx_initial")
|
||||
if [ "$initial_value" != "0.0000" ]; then
|
||||
fail "unexpected initial sphere V-x value '$initial_value'"
|
||||
fi
|
||||
record_state "sphere loaded"
|
||||
if ! replace_entry_text sphere_vx "$initial_value" \
|
||||
"$MGED_XMIN_TEST_DIR/sphere_vx_current" 5; then
|
||||
"$MGED_GUI_TEST_DIR/sphere_vx_current" 5; then
|
||||
fail "sphere V-x entry did not receive the expected value"
|
||||
fi
|
||||
record_state "sphere vertex edited"
|
||||
click_target apply_button
|
||||
record_state "sphere Apply dispatched"
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/primitive_applied"
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/primitive_applied"
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/primitive_result"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/primitive_result"; then
|
||||
fail "MGED did not report a primitive edit result"
|
||||
fi
|
||||
primitive_result=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/primitive_result")
|
||||
primitive_result=$(sed -n '1p' "$MGED_GUI_TEST_DIR/primitive_result")
|
||||
record_state "sphere edit applied"
|
||||
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/begin_pipe"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_ready" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_select" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_select_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_next" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_next_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_split" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_split_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_split_point" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_split_point_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_point" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_point_window"; then
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/begin_pipe"
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/pipe_ready" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_select" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_select_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_next" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_next_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_split" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_split_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_split_point" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_split_point_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_point" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/pipe_point_window"; then
|
||||
fail "pipe Faceplate edit did not become ready"
|
||||
fi
|
||||
record_state "pipe contextual Faceplate"
|
||||
click_target pipe_select 2
|
||||
record_state "pipe Select Point mode"
|
||||
click_target pipe_point 2
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/pipe_point_clicked"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_selected"; then
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/pipe_point_clicked"
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/pipe_selected"; then
|
||||
fail "pipe point was not selected through the viewport"
|
||||
fi
|
||||
pipe_keypoint=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/pipe_keypoint_current")
|
||||
pipe_keypoint=$(sed -n '1p' "$MGED_GUI_TEST_DIR/pipe_keypoint_current")
|
||||
record_state "pipe point selected"
|
||||
click_target pipe_next 2
|
||||
if ! wait_for_not_value "$MGED_XMIN_TEST_DIR/pipe_keypoint_current" \
|
||||
if ! wait_for_not_value "$MGED_GUI_TEST_DIR/pipe_keypoint_current" \
|
||||
"$pipe_keypoint"; then
|
||||
fail "pipe Next Point did not change the edit keypoint"
|
||||
fi
|
||||
@@ -789,75 +756,75 @@ click_target pipe_split 2
|
||||
record_state "pipe Split Segment mode"
|
||||
click_target pipe_split_point 2
|
||||
record_state "pipe segment split"
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/pipe_finish"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/pipe_done"; then
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/pipe_finish"
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/pipe_done"; then
|
||||
fail "pipe edit did not accept cleanly"
|
||||
fi
|
||||
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/begin_sketch"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_ready" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_create_line" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_create_line_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_zoom_in" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_zoom_in_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_reset" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_reset_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_dismiss" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_dismiss_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_canvas_start" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_canvas_start_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_canvas_end" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_canvas_end_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_scale_current" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_vertex_count_current"; then
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/begin_sketch"
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/sketch_ready" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_create_line" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_create_line_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_zoom_in" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_zoom_in_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_reset" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_reset_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_dismiss" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_dismiss_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_canvas_start" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_canvas_start_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_canvas_end" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_canvas_end_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_scale_current" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/sketch_vertex_count_current"; then
|
||||
fail "Sketch Editor controls did not become ready"
|
||||
fi
|
||||
record_state "Sketch Editor ready"
|
||||
sketch_scale=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/sketch_scale_current")
|
||||
sketch_scale=$(sed -n '1p' "$MGED_GUI_TEST_DIR/sketch_scale_current")
|
||||
click_target sketch_zoom_in
|
||||
if ! wait_for_not_value "$MGED_XMIN_TEST_DIR/sketch_scale_current" \
|
||||
if ! wait_for_not_value "$MGED_GUI_TEST_DIR/sketch_scale_current" \
|
||||
"$sketch_scale"; then
|
||||
fail "Sketch Editor Zoom In did not change the canvas scale"
|
||||
fi
|
||||
record_state "Sketch Editor zoomed"
|
||||
sketch_vertex_count=$(sed -n '1p' \
|
||||
"$MGED_XMIN_TEST_DIR/sketch_vertex_count_current")
|
||||
"$MGED_GUI_TEST_DIR/sketch_vertex_count_current")
|
||||
click_target sketch_create_line
|
||||
record_state "Sketch Editor Create Line mode"
|
||||
click_target sketch_canvas_start
|
||||
record_state "Sketch Editor line start"
|
||||
click_target sketch_canvas_end
|
||||
if ! wait_for_not_value "$MGED_XMIN_TEST_DIR/sketch_vertex_count_current" \
|
||||
if ! wait_for_not_value "$MGED_GUI_TEST_DIR/sketch_vertex_count_current" \
|
||||
"$sketch_vertex_count"; then
|
||||
fail "Sketch Editor did not add vertices for the new line"
|
||||
fi
|
||||
record_state "Sketch Editor line created"
|
||||
click_target sketch_reset
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/sketch_vertex_count_current" \
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/sketch_vertex_count_current" \
|
||||
"$sketch_vertex_count"; then
|
||||
fail "Sketch Editor Reset Sketch did not restore the fixture"
|
||||
fi
|
||||
record_state "Sketch Editor reset"
|
||||
click_target sketch_dismiss
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/sketch_closed"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/sketch_closed"; then
|
||||
fail "Sketch Editor did not dismiss cleanly"
|
||||
fi
|
||||
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/begin_matrix"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/matrix_dm_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/matrix_dm"; then
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/begin_matrix"
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/matrix_dm_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/matrix_dm"; then
|
||||
fail "MGED did not enter matrix edit mode"
|
||||
fi
|
||||
record_state "matrix edit ready"
|
||||
click_target matrix_dm 2
|
||||
record_state "matrix edit moved"
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/matrix_clicked"
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/matrix_clicked"
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/matrix_result"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/matrix_result"; then
|
||||
fail "MGED did not report a matrix edit result"
|
||||
fi
|
||||
|
||||
matrix_result=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/matrix_result")
|
||||
matrix_result=$(sed -n '1p' "$MGED_GUI_TEST_DIR/matrix_result")
|
||||
case "$matrix_result" in
|
||||
PASS:*) ;;
|
||||
*)
|
||||
@@ -870,39 +837,39 @@ capture_dm_snapshot raytrace_baseline
|
||||
|
||||
click_target main_tools_menu
|
||||
record_state "Tools menu embedded raytrace"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_control_menu" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_control_menu_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_control_menu" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_control_menu_window"; then
|
||||
fail "Tools menu did not expose the Raytrace Control Panel"
|
||||
fi
|
||||
activate_menu_target raytrace_control_menu
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_ready" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_size" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_size_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_destination" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_destination_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_button" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_button_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_active" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_active_window" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_dismiss" ||
|
||||
! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_dismiss_window"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_ready" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_size" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_size_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_destination" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_destination_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_button" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_button_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_active" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_active_window" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_dismiss" ||
|
||||
! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_dismiss_window"; then
|
||||
fail "Raytrace Control Panel controls did not become ready"
|
||||
fi
|
||||
record_state "Raytrace Control Panel"
|
||||
|
||||
raytrace_size=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/raytrace_size_initial")
|
||||
raytrace_size=$(sed -n '1p' "$MGED_GUI_TEST_DIR/raytrace_size_initial")
|
||||
if ! replace_entry_text raytrace_size "$raytrace_size" \
|
||||
"$MGED_XMIN_TEST_DIR/raytrace_size_current" "$RAYTRACE_SIZE"; then
|
||||
"$MGED_GUI_TEST_DIR/raytrace_size_current" "$RAYTRACE_SIZE"; then
|
||||
fail "Raytrace Control Panel size entry did not accept $RAYTRACE_SIZE"
|
||||
fi
|
||||
record_state "embedded raytrace size $RAYTRACE_SIZE"
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/raytrace_prepare_reference"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_reference_ready"; then
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/raytrace_prepare_reference"
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_reference_ready"; then
|
||||
fail "MGED did not prepare the standalone raytrace reference"
|
||||
fi
|
||||
reference_script=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/raytrace_reference_script")
|
||||
reference_image=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/raytrace_reference_image")
|
||||
reference_script=$(sed -n '1p' "$MGED_GUI_TEST_DIR/raytrace_reference_script")
|
||||
reference_image=$(sed -n '1p' "$MGED_GUI_TEST_DIR/raytrace_reference_image")
|
||||
if ! /bin/sh "$reference_script"; then
|
||||
fail "standalone reference raytrace failed"
|
||||
fi
|
||||
@@ -912,7 +879,7 @@ fi
|
||||
record_state "standalone raytrace reference complete"
|
||||
start_raytrace 1
|
||||
record_state "embedded raytrace started"
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/raytrace_complete" 1; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/raytrace_complete" 1; then
|
||||
fail "embedded raytrace did not complete"
|
||||
fi
|
||||
assert_raytrace_duration 1 "embedded raytrace"
|
||||
@@ -927,7 +894,7 @@ for mode in overlay interlay underlay; do
|
||||
click_target raytrace_framebuffer_menu
|
||||
record_state "Raytrace Framebuffer menu $mode"
|
||||
activate_menu_target "raytrace_$mode"
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/raytrace_overlay_current" "$layer"; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/raytrace_overlay_current" "$layer"; then
|
||||
fail "embedded framebuffer did not enter $mode mode"
|
||||
fi
|
||||
record_state "embedded framebuffer $mode"
|
||||
@@ -935,14 +902,14 @@ for mode in overlay interlay underlay; do
|
||||
done
|
||||
|
||||
assert_images_differ "embedded raytrace overlay" \
|
||||
"$MGED_XMIN_TEST_DIR/raytrace_baseline.ppm" \
|
||||
"$MGED_XMIN_TEST_DIR/raytrace_overlay.ppm"
|
||||
"$MGED_GUI_TEST_DIR/raytrace_baseline.ppm" \
|
||||
"$MGED_GUI_TEST_DIR/raytrace_overlay.ppm"
|
||||
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/raytrace_export_requested"
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_export_ready"; then
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/raytrace_export_requested"
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_export_ready"; then
|
||||
fail "MGED did not export the embedded framebuffer"
|
||||
fi
|
||||
embedded_image=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/raytrace_export_image")
|
||||
embedded_image=$(sed -n '1p' "$MGED_GUI_TEST_DIR/raytrace_export_image")
|
||||
if [ ! -s "$embedded_image" ]; then
|
||||
fail "MGED exported an empty embedded framebuffer image"
|
||||
fi
|
||||
@@ -955,42 +922,42 @@ record_state "embedded framebuffer matches standalone rt"
|
||||
# visible framebuffer image to remove.
|
||||
click_target raytrace_framebuffer_menu
|
||||
activate_menu_target raytrace_overlay
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/raytrace_overlay_current" 2; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/raytrace_overlay_current" 2; then
|
||||
fail "embedded framebuffer did not return to overlay mode"
|
||||
fi
|
||||
capture_dm_snapshot raytrace_active
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/raytrace_fb_current" 1; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/raytrace_fb_current" 1; then
|
||||
fail "embedded framebuffer was not active after raytracing"
|
||||
fi
|
||||
click_target raytrace_active
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/raytrace_fb_current" 0; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/raytrace_fb_current" 0; then
|
||||
fail "Raytrace Control Panel did not deactivate the framebuffer"
|
||||
fi
|
||||
record_state "embedded framebuffer inactive"
|
||||
wait_for_changed_dm_snapshot "framebuffer active toggle" \
|
||||
"$MGED_XMIN_TEST_DIR/raytrace_active.ppm" raytrace_inactive
|
||||
"$MGED_GUI_TEST_DIR/raytrace_active.ppm" raytrace_inactive
|
||||
click_target raytrace_active
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/raytrace_fb_current" 1; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/raytrace_fb_current" 1; then
|
||||
fail "Raytrace Control Panel did not reactivate the framebuffer"
|
||||
fi
|
||||
record_state "embedded framebuffer reactivated"
|
||||
|
||||
file_destination=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/raytrace_file_destination")
|
||||
embedded_destination=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/raytrace_destination_initial")
|
||||
file_destination=$(sed -n '1p' "$MGED_GUI_TEST_DIR/raytrace_file_destination")
|
||||
embedded_destination=$(sed -n '1p' "$MGED_GUI_TEST_DIR/raytrace_destination_initial")
|
||||
if ! replace_entry_text raytrace_destination "$embedded_destination" \
|
||||
"$MGED_XMIN_TEST_DIR/raytrace_destination_current" "$file_destination"; then
|
||||
"$MGED_GUI_TEST_DIR/raytrace_destination_current" "$file_destination"; then
|
||||
fail "Raytrace Control Panel did not accept a file destination"
|
||||
fi
|
||||
record_state "raytrace file destination"
|
||||
file_render_size=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/raytrace_size_current")
|
||||
file_render_size=$(sed -n '1p' "$MGED_GUI_TEST_DIR/raytrace_size_current")
|
||||
if ! replace_entry_text raytrace_size "$file_render_size" \
|
||||
"$MGED_XMIN_TEST_DIR/raytrace_size_current" "$RAYTRACE_SIZE"; then
|
||||
"$MGED_GUI_TEST_DIR/raytrace_size_current" "$RAYTRACE_SIZE"; then
|
||||
fail "Raytrace Control Panel did not restore size $RAYTRACE_SIZE for the file render"
|
||||
fi
|
||||
record_state "raytrace file size $RAYTRACE_SIZE"
|
||||
start_raytrace 2
|
||||
record_state "GUI file raytrace started"
|
||||
if ! wait_for_value "$MGED_XMIN_TEST_DIR/raytrace_complete" 2; then
|
||||
if ! wait_for_value "$MGED_GUI_TEST_DIR/raytrace_complete" 2; then
|
||||
fail "GUI file raytrace did not complete"
|
||||
fi
|
||||
assert_raytrace_duration 2 "GUI file raytrace"
|
||||
@@ -1000,25 +967,25 @@ fi
|
||||
assert_raw_images_equal "GUI file raytrace" "$reference_image" "$file_destination"
|
||||
record_state "GUI raytrace matches standalone rt"
|
||||
if ! replace_entry_text raytrace_destination "$file_destination" \
|
||||
"$MGED_XMIN_TEST_DIR/raytrace_destination_current" "$embedded_destination"; then
|
||||
"$MGED_GUI_TEST_DIR/raytrace_destination_current" "$embedded_destination"; then
|
||||
fail "Raytrace Control Panel did not restore the embedded destination"
|
||||
fi
|
||||
record_state "embedded raytrace destination restored"
|
||||
|
||||
click_target raytrace_dismiss
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/raytrace_closed"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/raytrace_closed"; then
|
||||
fail "Raytrace Control Panel did not dismiss cleanly"
|
||||
fi
|
||||
"$XMIN_CTL" activate "$main_window"
|
||||
"$GUI_TEST_CTL" activate "$main_window"
|
||||
click_target main_view_menu
|
||||
record_state "post-raytrace View menu responsiveness"
|
||||
"$XMIN_CTL" key escape
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/raytrace_responsive"
|
||||
"$GUI_TEST_CTL" key escape
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/raytrace_responsive"
|
||||
|
||||
if ! wait_for_file "$MGED_XMIN_TEST_DIR/result"; then
|
||||
if ! wait_for_file "$MGED_GUI_TEST_DIR/result"; then
|
||||
fail "MGED did not remain responsive after embedded raytrace"
|
||||
fi
|
||||
result=$(sed -n '1p' "$MGED_XMIN_TEST_DIR/result")
|
||||
result=$(sed -n '1p' "$MGED_GUI_TEST_DIR/result")
|
||||
case "$result" in
|
||||
PASS:*) ;;
|
||||
*)
|
||||
@@ -1026,7 +993,7 @@ case "$result" in
|
||||
;;
|
||||
esac
|
||||
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_XMIN_TEST_DIR/finish"
|
||||
"$CMAKE_COMMAND" -E touch "$MGED_GUI_TEST_DIR/finish"
|
||||
|
||||
wait "$MGED_PID"
|
||||
MGED_PID=""
|
||||
|
||||
@@ -20,35 +20,35 @@
|
||||
###
|
||||
# Exercise MGED's BoT editor through its live controls.
|
||||
|
||||
source $::env(MGED_XMIN_GUI_LIBRARY)
|
||||
source $::env(MGED_GUI_TEST_LIBRARY)
|
||||
|
||||
namespace eval ::mged::xmin::bot {}
|
||||
|
||||
proc ::mged::xmin::bot::find_combobox {root first_value} {
|
||||
foreach widget [::xmin::test::descendants $root] {
|
||||
foreach widget [::gui::test::descendants $root] {
|
||||
if {[winfo class $widget] eq "TCombobox" &&
|
||||
[lindex [$widget cget -values] 0] eq $first_value} {
|
||||
return $widget
|
||||
}
|
||||
}
|
||||
::mged::xmin::test::fail \
|
||||
::mged::gui::test::fail \
|
||||
"$root has no combobox beginning with '$first_value'"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::bot::confirm_action {editor button_text} {
|
||||
set button [::mged::xmin::test::find_widget_by_text $editor $button_text]
|
||||
set button [::mged::gui::test::find_widget_by_text $editor $button_text]
|
||||
$button invoke
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
|
||||
set confirmation $editor.confirmDialog
|
||||
::mged::xmin::test::require_mapped $confirmation \
|
||||
::mged::gui::test::require_mapped $confirmation \
|
||||
"$button_text confirmation"
|
||||
[::mged::xmin::test::find_widget_by_text $confirmation Yes] invoke
|
||||
::mged::xmin::test::settle
|
||||
[::mged::gui::test::find_widget_by_text $confirmation Yes] invoke
|
||||
::mged::gui::test::settle
|
||||
}
|
||||
|
||||
proc ::mged::xmin::bot::require_counts {bot vertices faces description} {
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength [get $bot V]] == $vertices &&
|
||||
[llength [get $bot F]] == $faces
|
||||
} "$description does not have $vertices vertices and $faces faces"
|
||||
@@ -59,17 +59,17 @@ proc ::mged::xmin::bot::exercise_editor {id top} {
|
||||
{0 0 0} {100 0 0} {0 100 0} {0 0 0} {999 999 999}
|
||||
} F {{0 1 2} {3 1 2}}
|
||||
|
||||
::mged::xmin::test::with_dialog_answer .$id.botname "BoT to Edit" \
|
||||
::mged::gui::test::with_dialog_answer .$id.botname "BoT to Edit" \
|
||||
.$id.botname.mid.ent xmin_bot.s .$id.botname.bot.button0 \
|
||||
[list ::mged::xmin::test::invoke $top {Tools {BoT Edit Tool}}]
|
||||
[list ::mged::gui::test::invoke $top {Tools {BoT Edit Tool}}]
|
||||
|
||||
set editor .botedit
|
||||
::mged::xmin::test::require_mapped $editor "BoT Edit Tool"
|
||||
::mged::gui::test::require_mapped $editor "BoT Edit Tool"
|
||||
require_counts xmin_bot.s.edit 5 2 "initial working BoT"
|
||||
|
||||
set mode [find_combobox $editor Surface]
|
||||
set orientation [find_combobox $editor Unoriented]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$mode current] == 0 && [$orientation current] == 0
|
||||
} "BoT Editor did not display the initial mode and orientation"
|
||||
|
||||
@@ -77,18 +77,18 @@ proc ::mged::xmin::bot::exercise_editor {id top} {
|
||||
event generate $mode <<ComboboxSelected>>
|
||||
$orientation current 1
|
||||
event generate $orientation <<ComboboxSelected>>
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[bot get type xmin_bot.s.edit] eq "solid" &&
|
||||
[bot get orientation xmin_bot.s.edit] eq "ccw"
|
||||
} "BoT Editor did not apply mode and orientation changes"
|
||||
|
||||
[::mged::xmin::test::find_widget_by_text $editor {Remove Selected}] invoke
|
||||
::mged::xmin::test::settle
|
||||
[::mged::gui::test::find_widget_by_text $editor {Remove Selected}] invoke
|
||||
::mged::gui::test::settle
|
||||
require_counts xmin_bot.s.edit 3 1 "simplified working BoT"
|
||||
|
||||
confirm_action $editor {Start Over}
|
||||
require_counts xmin_bot.s.edit 5 2 "reverted working BoT"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[bot get type xmin_bot.s.edit] eq "surface" &&
|
||||
[bot get orientation xmin_bot.s.edit] eq "none" &&
|
||||
[$mode current] == 0 && [$orientation current] == 0
|
||||
@@ -102,13 +102,13 @@ proc ::mged::xmin::bot::exercise_editor {id top} {
|
||||
{Remove Unused Vertices} {Remove Duplicate Vertices}
|
||||
{Remove Duplicate Faces}
|
||||
} {
|
||||
[::mged::xmin::test::find_widget_by_text $editor $option] invoke
|
||||
[::mged::gui::test::find_widget_by_text $editor $option] invoke
|
||||
}
|
||||
[::mged::xmin::test::find_widget_by_text $editor {Remove Selected}] invoke
|
||||
::mged::xmin::test::settle
|
||||
[::mged::gui::test::find_widget_by_text $editor {Remove Selected}] invoke
|
||||
::mged::gui::test::settle
|
||||
confirm_action $editor Accept
|
||||
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
![winfo exists $editor] && ![exists xmin_bot.s.edit] &&
|
||||
[bot get type xmin_bot.s] eq "solid" &&
|
||||
[bot get orientation xmin_bot.s] eq "ccw"
|
||||
@@ -117,8 +117,8 @@ proc ::mged::xmin::bot::exercise_editor {id top} {
|
||||
}
|
||||
|
||||
proc ::mged::xmin::bot::run {id top} {
|
||||
set database [file join $::env(XMIN_TEST_DIR) bot.g]
|
||||
cd $::env(XMIN_TEST_DIR)
|
||||
set database [file join $::env(GUI_TEST_DIR) bot.g]
|
||||
cd $::env(GUI_TEST_DIR)
|
||||
file delete -force $database
|
||||
opendb $database y
|
||||
title {Xmin MGED BoT editor regression}
|
||||
@@ -126,7 +126,7 @@ proc ::mged::xmin::bot::run {id top} {
|
||||
exercise_editor $id $top
|
||||
}
|
||||
|
||||
::mged::xmin::test::start ::mged::xmin::bot::run \
|
||||
::mged::gui::test::start ::mged::xmin::bot::run \
|
||||
{MGED BoT editor} {MGED BoT editor regression}
|
||||
|
||||
# Local Variables:
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
###
|
||||
# Exercise stateful MGED control panels through their live Tk widgets.
|
||||
|
||||
if {![info exists ::env(XMIN_GUI_LIBRARY)] ||
|
||||
![info exists ::env(XMIN_TEST_DIR)]} {
|
||||
puts stderr "XMIN_GUI_LIBRARY and XMIN_TEST_DIR are required"
|
||||
if {![info exists ::env(GUI_TEST_LIBRARY)] ||
|
||||
![info exists ::env(GUI_TEST_DIR)]} {
|
||||
puts stderr "GUI_TEST_LIBRARY and GUI_TEST_DIR are required"
|
||||
exit 2
|
||||
}
|
||||
source $::env(XMIN_GUI_LIBRARY)
|
||||
::xmin::test::capture_background_errors
|
||||
source $::env(GUI_TEST_LIBRARY)
|
||||
::gui::test::capture_background_errors
|
||||
|
||||
namespace eval ::mged::xmin {
|
||||
variable adc_distance_tolerance 0.1
|
||||
@@ -84,10 +84,10 @@ proc ::mged::xmin::set_view {azimuth elevation center_point view_size} {
|
||||
}
|
||||
|
||||
proc ::mged::xmin::invoke {root labels} {
|
||||
::xmin::test::write progress "invoke: [join $labels { > }]"
|
||||
::xmin::test::invoke_menu_entry $root $labels
|
||||
::gui::test::write progress "invoke: [join $labels { > }]"
|
||||
::gui::test::invoke_menu_entry $root $labels
|
||||
settle
|
||||
::xmin::test::write progress "invoked: [join $labels { > }]"
|
||||
::gui::test::write progress "invoked: [join $labels { > }]"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::exercise_view_ring {id top} {
|
||||
@@ -99,7 +99,7 @@ proc ::mged::xmin::exercise_view_ring {id top} {
|
||||
set second [set_view 40 30 {-4 5 6} 200]
|
||||
invoke $top {ViewRing {Add View}}
|
||||
set second_id $view_ring($id)
|
||||
::xmin::test::require {[llength $mged_gui($id,views)] == 2} \
|
||||
::gui::test::require {[llength $mged_gui($id,views)] == 2} \
|
||||
"ViewRing did not store two views"
|
||||
|
||||
set_view 0 0 {0 0 0} 50
|
||||
@@ -118,9 +118,9 @@ proc ::mged::xmin::exercise_view_ring {id top} {
|
||||
|
||||
set delete_menu $top.menubar.viewring.delete
|
||||
$delete_menu invoke 0
|
||||
::xmin::test::require {[llength $mged_gui($id,views)] == 1} \
|
||||
::gui::test::require {[llength $mged_gui($id,views)] == 1} \
|
||||
"ViewRing did not delete the selected stored view"
|
||||
::xmin::test::require {$view_ring($id) == $second_id} \
|
||||
::gui::test::require {$view_ring($id) == $second_id} \
|
||||
"ViewRing deletion left its selection on a deleted view"
|
||||
invoke $top {ViewRing {Next View}}
|
||||
require_near [view_state] $second "ViewRing traversal after deletion"
|
||||
@@ -131,9 +131,9 @@ proc ::mged::xmin::exercise_grid {id top} {
|
||||
|
||||
invoke $top {Tools {Grid Control Panel}}
|
||||
set panel $top.grid_control
|
||||
::xmin::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
::gui::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
"Grid Control Panel did not open"
|
||||
::xmin::test::require {[wm title $panel] eq "Grid Control Panel ($id)"} \
|
||||
::gui::test::require {[wm title $panel] eq "Grid Control Panel ($id)"} \
|
||||
"Grid Control Panel has an unexpected title"
|
||||
|
||||
foreach setting {anchor rh rv mrh mrv draw snap} {
|
||||
@@ -154,7 +154,7 @@ proc ::mged::xmin::exercise_grid {id top} {
|
||||
require_near [rset grid rv] {3.5} "vertical grid spacing"
|
||||
require_near [rset grid mrh] {7} "horizontal major-grid spacing"
|
||||
require_near [rset grid mrv] {9} "vertical major-grid spacing"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[rset grid draw] == 1 && [rset grid snap] == 1 &&
|
||||
$mged_gui($id,grid_draw) == 1 && $mged_gui($id,grid_snap) == 1
|
||||
} "Grid Control Panel did not synchronize its render and GUI state"
|
||||
@@ -169,7 +169,7 @@ proc ::mged::xmin::exercise_grid {id top} {
|
||||
$panel.applyB invoke
|
||||
$panel.resetB invoke
|
||||
$panel.dismissB invoke
|
||||
::xmin::test::require {![winfo exists $panel]} \
|
||||
::gui::test::require {![winfo exists $panel]} \
|
||||
"Grid Control Panel did not dismiss"
|
||||
}
|
||||
|
||||
@@ -179,9 +179,9 @@ proc ::mged::xmin::exercise_adc {id top} {
|
||||
|
||||
invoke $top {Tools {ADC Control Panel}}
|
||||
set panel $top.adc_control
|
||||
::xmin::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
::gui::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
"ADC Control Panel did not open"
|
||||
::xmin::test::require {[wm title $panel] eq "ADC Control Panel ($id)"} \
|
||||
::gui::test::require {[wm title $panel] eq "ADC Control Panel ($id)"} \
|
||||
"ADC Control Panel has an unexpected title"
|
||||
set reset_position [adc xyz]
|
||||
|
||||
@@ -205,18 +205,18 @@ proc ::mged::xmin::exercise_adc {id top} {
|
||||
$adc_distance_tolerance
|
||||
require_near [adc a1] {15} "ADC first angle"
|
||||
require_near [adc a2] {75} "ADC second angle"
|
||||
::xmin::test::require {[adc draw] == 1} \
|
||||
::gui::test::require {[adc draw] == 1} \
|
||||
"ADC Control Panel did not enable the cursor"
|
||||
|
||||
$panel.resetB invoke
|
||||
require_near [adc xyz] $reset_position "reset ADC position"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[adc draw] == 1 && $mged_adc_control($id,draw) == 1
|
||||
} "ADC Control Panel reset did not preserve and reload the draw setting"
|
||||
set mged_adc_control($id,draw) 0
|
||||
$panel.applyB invoke
|
||||
$panel.dismissB invoke
|
||||
::xmin::test::require {![winfo exists $panel]} \
|
||||
::gui::test::require {![winfo exists $panel]} \
|
||||
"ADC Control Panel did not dismiss"
|
||||
}
|
||||
|
||||
@@ -225,42 +225,42 @@ proc ::mged::xmin::exercise_font_persistence {id top} {
|
||||
|
||||
invoke $top {File Preferences Fonts}
|
||||
set panel $top.font_scheme
|
||||
::xmin::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
::gui::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
"Fonts panel did not open"
|
||||
::xmin::test::require {[wm title $panel] eq "Fonts"} \
|
||||
::gui::test::require {[wm title $panel] eq "Fonts"} \
|
||||
"Fonts panel has an unexpected title"
|
||||
|
||||
set text_menu $panel._TextMB.menu
|
||||
set font_index [$text_menu index {courier 18}]
|
||||
::xmin::test::require {$font_index ne "none"} \
|
||||
::gui::test::require {$font_index ne "none"} \
|
||||
"Fonts panel does not offer courier 18"
|
||||
$text_menu invoke $font_index
|
||||
$panel.applyB invoke
|
||||
|
||||
::xmin::test::require {[font configure text_font -size] == 18} \
|
||||
::gui::test::require {[font configure text_font -size] == 18} \
|
||||
"Fonts panel did not apply the text-font size"
|
||||
::xmin::test::require {[dict get $mged_default(text_font) -size] == 18} \
|
||||
::gui::test::require {[dict get $mged_default(text_font) -size] == 18} \
|
||||
"Fonts panel did not update the persisted text-font setting"
|
||||
|
||||
invoke $top {File {Create/Update .mgedrc}}
|
||||
set rcfile [file join $::env(XMIN_TEST_DIR) .mgedrc]
|
||||
::xmin::test::require {[file exists $rcfile]} \
|
||||
set rcfile [file join $::env(GUI_TEST_DIR) .mgedrc]
|
||||
::gui::test::require {[file exists $rcfile]} \
|
||||
"Create/Update .mgedrc did not create the isolated preferences file"
|
||||
set channel [open $rcfile r]
|
||||
set contents [read $channel]
|
||||
close $channel
|
||||
set expected [list set mged_default(text_font) $mged_default(text_font)]
|
||||
::xmin::test::require {[lsearch -exact [split $contents \n] $expected] >= 0} \
|
||||
::gui::test::require {[lsearch -exact [split $contents \n] $expected] >= 0} \
|
||||
".mgedrc did not contain the applied text-font setting"
|
||||
|
||||
$panel.dismissB invoke
|
||||
::xmin::test::require {![winfo exists $panel]} \
|
||||
::gui::test::require {![winfo exists $panel]} \
|
||||
"Fonts panel did not dismiss"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::dismiss_about {expected_title} {
|
||||
variable about_seen
|
||||
foreach widget [linsert [::xmin::test::descendants .] 0 .] {
|
||||
foreach widget [linsert [::gui::test::descendants .] 0 .] {
|
||||
if {[winfo toplevel $widget] ne $widget ||
|
||||
![winfo ismapped $widget] || [wm title $widget] ne $expected_title} {
|
||||
continue
|
||||
@@ -281,7 +281,7 @@ proc ::mged::xmin::exercise_about {top} {
|
||||
set about_seen ""
|
||||
after 25 [list ::mged::xmin::dismiss_about $expected_title]
|
||||
invoke $top {Help {About MGED}}
|
||||
::xmin::test::require {$about_seen eq $expected_title} \
|
||||
::gui::test::require {$about_seen eq $expected_title} \
|
||||
"About MGED did not display its dialog"
|
||||
}
|
||||
|
||||
@@ -292,10 +292,10 @@ proc ::mged::xmin::finish {status message} {
|
||||
}
|
||||
set finished 1
|
||||
catch {update}
|
||||
lassign [::xmin::test::check_background_errors $status $message] \
|
||||
lassign [::gui::test::check_background_errors $status $message] \
|
||||
status message
|
||||
puts $message
|
||||
::xmin::test::write result $message
|
||||
::gui::test::write result $message
|
||||
if {$status != 0} {
|
||||
puts stderr $message
|
||||
}
|
||||
@@ -327,12 +327,12 @@ proc ::mged::xmin::run {} {
|
||||
}
|
||||
|
||||
set versions {}
|
||||
foreach {package minimum} {Itcl 3.4 Itk 3.4 Iwidgets 4.1.1} {
|
||||
foreach {package minimum} {Itcl 4.3.0 Itk 4.2.3 Iwidgets 4.1.1} {
|
||||
set version [package require $package $minimum]
|
||||
lappend versions "$package $version"
|
||||
}
|
||||
::xmin::test::write package_versions [join $versions \n]
|
||||
set ::env(HOME) $::env(XMIN_TEST_DIR)
|
||||
::gui::test::write package_versions [join $versions \n]
|
||||
set ::env(HOME) $::env(GUI_TEST_DIR)
|
||||
|
||||
exercise_view_ring $id $top
|
||||
exercise_grid $id $top
|
||||
@@ -348,7 +348,7 @@ proc ::mged::xmin::run_checked {} {
|
||||
if {[dict exists $options -errorinfo]} {
|
||||
set error_info [dict get $options -errorinfo]
|
||||
puts stderr $error_info
|
||||
::xmin::test::write tcl_error_debug $error_info
|
||||
::gui::test::write tcl_error_debug $error_info
|
||||
}
|
||||
finish 1 "FAIL: MGED control-panel regression: $message"
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
# any GUI action or database edit under test: menu, entry, button, and display
|
||||
# actions arrive through the X server.
|
||||
|
||||
set xmin_test_dir $::env(MGED_XMIN_TEST_DIR)
|
||||
source $::env(XMIN_GUI_LIBRARY)
|
||||
set xmin_test_dir $::env(MGED_GUI_TEST_DIR)
|
||||
source $::env(GUI_TEST_LIBRARY)
|
||||
|
||||
set xmin_deadline_ms 240000
|
||||
set xmin_poll_ms 25
|
||||
@@ -45,11 +45,11 @@ set xmin_pipe_split_y 948.0
|
||||
set xmin_raytrace_completion_settle_ms 500
|
||||
|
||||
proc xmin_write {name contents} {
|
||||
::xmin::test::write $name $contents
|
||||
::gui::test::write $name $contents
|
||||
}
|
||||
|
||||
proc xmin_publish_target {name widget} {
|
||||
::xmin::test::publish_target $name $widget
|
||||
::gui::test::publish_target $name $widget
|
||||
}
|
||||
|
||||
proc xmin_publish_faceplate_target {name widget bv_x bv_y} {
|
||||
@@ -75,11 +75,11 @@ proc xmin_publish_model_point_target {name widget model_point} {
|
||||
}
|
||||
|
||||
proc xmin_descendants {widget} {
|
||||
::xmin::test::descendants $widget
|
||||
::gui::test::descendants $widget
|
||||
}
|
||||
|
||||
proc xmin_find_widget {root class text} {
|
||||
::xmin::test::find_widget $root $class $text
|
||||
::gui::test::find_widget $root $class $text
|
||||
}
|
||||
|
||||
proc xmin_menu_inventory_walk {menu path inventory_name visited_name} {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,11 +20,12 @@
|
||||
###
|
||||
# Exercise MGED's Combination and Attribute editors through live widgets.
|
||||
|
||||
source $::env(MGED_XMIN_GUI_LIBRARY)
|
||||
source $::env(MGED_GUI_TEST_LIBRARY)
|
||||
source [file join [file dirname $::env(GUI_TEST_LIBRARY)] sketch_test.tcl]
|
||||
|
||||
namespace eval ::mged::xmin::editors {}
|
||||
proc ::mged::xmin::editors::confirm_combination_overwrite {button} {
|
||||
::mged::xmin::test::with_dialog_answer .mged_dialog Warning! "" "" \
|
||||
::mged::gui::test::with_dialog_answer .mged_dialog Warning! "" "" \
|
||||
.mged_dialog.bot.button0 [list $button invoke]
|
||||
}
|
||||
|
||||
@@ -32,18 +33,18 @@ proc ::mged::xmin::editors::confirm_combination_overwrite {button} {
|
||||
proc ::mged::xmin::editors::exercise_combination {id top} {
|
||||
global comb_control
|
||||
|
||||
::mged::xmin::test::invoke $top {Edit {Combination Editor}}
|
||||
::mged::gui::test::invoke $top {Edit {Combination Editor}}
|
||||
set editor .$id.comb
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $editor] && [winfo ismapped $editor]
|
||||
} "Combination Editor did not open"
|
||||
|
||||
::mged::xmin::test::set_entry $editor.nameE xmin_group.c
|
||||
::mged::gui::test::set_entry $editor.nameE xmin_group.c
|
||||
focus $editor.nameE
|
||||
event generate $editor.nameE <KeyPress> -keysym Return
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
set original_expression [string trim [$editor.combT get 1.0 end]]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string first "xmin_left.s" $original_expression] >= 0 &&
|
||||
[string first "xmin_right.s" $original_expression] >= 0
|
||||
} "Combination Editor did not load the selected combination tree"
|
||||
@@ -56,10 +57,10 @@ proc ::mged::xmin::editors::exercise_combination {id top} {
|
||||
set comb_control($id,inherit) Yes
|
||||
$editor.shaderMB.m invoke plastic
|
||||
confirm_combination_overwrite $editor.applyB
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
|
||||
set values [get_comb xmin_group.c]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lindex $values 1] eq "10 20 30" &&
|
||||
[lindex [lindex $values 2] 0] eq "plastic" &&
|
||||
[lindex $values 3] eq "Yes" &&
|
||||
@@ -69,8 +70,8 @@ proc ::mged::xmin::editors::exercise_combination {id top} {
|
||||
$editor.combT delete 1.0 end
|
||||
$editor.combT insert end {u xmin_left.s}
|
||||
$editor.resetB invoke
|
||||
::mged::xmin::test::settle
|
||||
::xmin::test::require {
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {
|
||||
[string first "- xmin_right.s" [$editor.combT get 1.0 end]] >= 0
|
||||
} "Combination Editor Reset did not reload database state"
|
||||
|
||||
@@ -81,7 +82,7 @@ proc ::mged::xmin::editors::exercise_combination {id top} {
|
||||
set comb_control($id,los) 80
|
||||
confirm_combination_overwrite $editor.applyB
|
||||
set values [get_comb xmin_group.c]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lindex $values 5] eq "Yes" &&
|
||||
[lindex $values 6] == 1201 &&
|
||||
[lindex $values 7] == 0 &&
|
||||
@@ -90,27 +91,27 @@ proc ::mged::xmin::editors::exercise_combination {id top} {
|
||||
} "Combination Editor did not persist region properties"
|
||||
|
||||
confirm_combination_overwrite $editor.okB
|
||||
::xmin::test::require {![winfo exists $editor]} \
|
||||
::gui::test::require {![winfo exists $editor]} \
|
||||
"Combination Editor did not close after OK"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::editors::load_attribute_object {editor object_name} {
|
||||
set object_entry $editor.fr_obj.obj_e
|
||||
::mged::xmin::test::set_entry $object_entry $object_name
|
||||
::mged::gui::test::set_entry $object_entry $object_name
|
||||
focus $object_entry
|
||||
event generate $object_entry <KeyPress> -keysym Return
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
}
|
||||
|
||||
proc ::mged::xmin::editors::select_attribute {listbox name} {
|
||||
set index [lsearch -exact [$listbox get 0 end] $name]
|
||||
if {$index < 0} {
|
||||
::mged::xmin::test::fail "Attribute Editor did not list '$name'"
|
||||
::mged::gui::test::fail "Attribute Editor did not list '$name'"
|
||||
}
|
||||
$listbox selection clear 0 end
|
||||
$listbox selection set $index
|
||||
event generate $listbox <<ListboxSelect>>
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
}
|
||||
|
||||
proc ::mged::xmin::editors::set_attribute_value {text value} {
|
||||
@@ -118,83 +119,83 @@ proc ::mged::xmin::editors::set_attribute_value {text value} {
|
||||
$text delete 1.0 end
|
||||
$text insert end $value
|
||||
event generate $text <KeyRelease> -keysym a
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
}
|
||||
|
||||
proc ::mged::xmin::editors::exercise_attributes {id top} {
|
||||
::mged::xmin::test::invoke $top {Edit {Attribute Editor}}
|
||||
::mged::gui::test::invoke $top {Edit {Attribute Editor}}
|
||||
set editor .${id}_attr_edit
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength [info commands $editor]] == 1 &&
|
||||
[winfo exists $editor] && [winfo ismapped $editor]
|
||||
} "Attribute Editor did not open"
|
||||
|
||||
load_attribute_object $editor xmin_attr.s
|
||||
set listbox [::mged::xmin::test::find_descendant $editor Listbox]
|
||||
set value_text [::mged::xmin::test::find_descendant $editor Text]
|
||||
set listbox [::mged::gui::test::find_descendant $editor Listbox]
|
||||
set value_text [::mged::gui::test::find_descendant $editor Text]
|
||||
select_attribute $listbox existing
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string trim [$value_text get 1.0 end]] eq "original"
|
||||
} "Attribute Editor did not load the selected attribute value"
|
||||
|
||||
set_attribute_value $value_text pending
|
||||
$editor.fr_attr.frc1.reset_sel invoke
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string trim [$value_text get 1.0 end]] eq "original"
|
||||
} "Attribute Editor reset selected did not restore database state"
|
||||
|
||||
set_attribute_value $value_text changed
|
||||
$editor.frc.apply invoke
|
||||
::xmin::test::require {[attr get xmin_attr.s existing] eq "changed"} \
|
||||
::gui::test::require {[attr get xmin_attr.s existing] eq "changed"} \
|
||||
"Attribute Editor Apply did not persist an edited value"
|
||||
|
||||
$editor.fr_attr.fr_new.new invoke
|
||||
set name_entry $editor.fr_attr.fr_new.attr_e
|
||||
::mged::xmin::test::set_entry $name_entry added
|
||||
::mged::gui::test::set_entry $name_entry added
|
||||
focus $name_entry
|
||||
event generate $name_entry <KeyPress> -keysym Return
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
set_attribute_value $value_text {new value}
|
||||
$editor.frc.apply invoke
|
||||
::xmin::test::require {[attr get xmin_attr.s added] eq "new value"} \
|
||||
::gui::test::require {[attr get xmin_attr.s added] eq "new value"} \
|
||||
"Attribute Editor did not create a new attribute"
|
||||
|
||||
select_attribute $listbox added
|
||||
$editor.fr_attr.frc1.delete_selected invoke
|
||||
$editor.frc.apply invoke
|
||||
::xmin::test::require {[catch {attr get xmin_attr.s added}]} \
|
||||
::gui::test::require {[catch {attr get xmin_attr.s added}]} \
|
||||
"Attribute Editor did not delete the selected attribute"
|
||||
|
||||
select_attribute $listbox existing
|
||||
set_attribute_value $value_text discarded
|
||||
$editor.fr_attr.frc1.reset_all invoke
|
||||
select_attribute $listbox existing
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string trim [$value_text get 1.0 end]] eq "changed"
|
||||
} "Attribute Editor reset all did not discard pending changes"
|
||||
|
||||
set_attribute_value $value_text final
|
||||
$editor.frc.ok invoke
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
![winfo exists $editor] && [attr get xmin_attr.s existing] eq "final"
|
||||
} "Attribute Editor OK did not persist and close"
|
||||
|
||||
::mged::xmin::test::invoke $top {Edit {Attribute Editor}}
|
||||
::mged::gui::test::invoke $top {Edit {Attribute Editor}}
|
||||
load_attribute_object $editor xmin_attr.s
|
||||
set listbox [::mged::xmin::test::find_descendant $editor Listbox]
|
||||
set listbox [::mged::gui::test::find_descendant $editor Listbox]
|
||||
$editor do_new_obj
|
||||
set value_text [::mged::xmin::test::find_descendant $editor Text]
|
||||
set value_text [::mged::gui::test::find_descendant $editor Text]
|
||||
select_attribute $listbox existing
|
||||
set_attribute_value $value_text unsaved
|
||||
$editor.frc.dismiss invoke
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
![winfo exists $editor] && [attr get xmin_attr.s existing] eq "final"
|
||||
} "Attribute Editor Dismiss saved a pending edit or failed to close"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::editors::run {id top} {
|
||||
set database [file join $::env(XMIN_TEST_DIR) editors.g]
|
||||
cd $::env(XMIN_TEST_DIR)
|
||||
set database [file join $::env(GUI_TEST_DIR) editors.g]
|
||||
cd $::env(GUI_TEST_DIR)
|
||||
file delete -force $database
|
||||
opendb $database y
|
||||
title {Xmin MGED editor regression}
|
||||
@@ -204,12 +205,12 @@ proc ::mged::xmin::editors::run {id top} {
|
||||
make xmin_attr.s arb8
|
||||
attr set xmin_attr.s existing original
|
||||
|
||||
::xmin::test::exercise_sketch_segments Sketch_carc Sketch_bezier MGED ::mged::xmin::editors
|
||||
::gui::test::exercise_sketch_segments Sketch_carc Sketch_bezier MGED ::mged::xmin::editors
|
||||
exercise_combination $id $top
|
||||
exercise_attributes $id $top
|
||||
}
|
||||
|
||||
::mged::xmin::test::start ::mged::xmin::editors::run \
|
||||
::mged::gui::test::start ::mged::xmin::editors::run \
|
||||
{MGED Combination and Attribute editors} {MGED editor regression}
|
||||
|
||||
# Local Variables:
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
###
|
||||
# Exercise MGED command manuals, searches, and help dialogs.
|
||||
|
||||
source $::env(MGED_XMIN_GUI_LIBRARY)
|
||||
source $::env(MGED_GUI_TEST_LIBRARY)
|
||||
|
||||
namespace eval ::mged::xmin::help {
|
||||
variable exec_arguments {}
|
||||
@@ -32,94 +32,106 @@ proc ::mged::xmin::help::record_exec {args} {
|
||||
}
|
||||
|
||||
proc ::mged::xmin::help::exercise_command_manual {top} {
|
||||
::mged::xmin::test::invoke $top {Help {Command Manual Pages}}
|
||||
::mged::gui::test::invoke $top {Help {Command Manual Pages}}
|
||||
set browser .mgedMan
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength [info commands $browser]] == 1 &&
|
||||
[winfo exists $browser] && [winfo ismapped $browser]
|
||||
} "Command Manual Pages did not open the internal browser"
|
||||
|
||||
set toc [$browser component manpagelistbox]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $toc] && [$toc size] > 100 &&
|
||||
[lsearch -exact [$toc get 0 end] rt] >= 0
|
||||
} "manual browser did not populate the program-page table of contents"
|
||||
|
||||
man rt
|
||||
set selection [$toc curselection]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength $selection] == 1 && [$toc get $selection] eq "rt"
|
||||
} "man rt did not select and load the rt manual page"
|
||||
::xmin::test::require {
|
||||
|
||||
event generate $toc <<ListboxSelect>>
|
||||
::mged::gui::test::settle
|
||||
|
||||
man search
|
||||
set html_view [$browser component browser].htmlview
|
||||
set html_widget [$html_view html]
|
||||
$html_view goto {#hierarchy_performance}
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {[lindex [$html_widget yview] 0] > 0.0} \
|
||||
"manual browser did not follow an in-page hyperlink"
|
||||
|
||||
::gui::test::require {
|
||||
[catch {man xmin_page_that_does_not_exist} message] &&
|
||||
[string first "couldn't find manual page" $message] >= 0
|
||||
} "missing manual page lookup did not report a useful error"
|
||||
|
||||
man -k ray
|
||||
::xmin::test::require {[$toc size] > 0} \
|
||||
::gui::test::require {[$toc size] > 0} \
|
||||
"short manual search returned no results"
|
||||
$browser search "ray tracing" full
|
||||
::xmin::test::require {[$toc size] > 0} \
|
||||
::gui::test::require {[$toc size] > 0} \
|
||||
"full-text manual search returned no results"
|
||||
set search_entry [$browser component search_frame].entry
|
||||
$search_entry delete 0 end
|
||||
$search_entry insert 0 geometry
|
||||
event generate $search_entry <KeyRelease>
|
||||
::mged::xmin::test::settle
|
||||
::xmin::test::require {[$toc size] > 0} \
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {[$toc size] > 0} \
|
||||
"manual browser search widget did not refresh results"
|
||||
[$browser component search_frame].clear invoke
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$toc size] > 100 && [lsearch -exact [$toc get 0 end] rt] >= 0
|
||||
} "manual browser Clear did not restore the table of contents"
|
||||
$browser deactivate
|
||||
}
|
||||
|
||||
proc ::mged::xmin::help::exercise_manual_search {top} {
|
||||
::mged::xmin::test::with_dialog_answer $top.mansearch {Manual Search} \
|
||||
::mged::gui::test::with_dialog_answer $top.mansearch {Manual Search} \
|
||||
$top.mansearch.mid.ent {ray tracing} $top.mansearch.bot.button0 \
|
||||
[list ::mged::xmin::test::invoke $top {Help {Manual Search}}]
|
||||
[list ::mged::gui::test::invoke $top {Help {Manual Search}}]
|
||||
set browser .mgedMan
|
||||
set toc [$browser component manpagelistbox]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo ismapped $browser] && [$toc size] > 0
|
||||
} "Manual Search did not display ranked internal-browser results"
|
||||
$browser deactivate
|
||||
}
|
||||
|
||||
proc ::mged::xmin::help::exercise_apropos {top} {
|
||||
::mged::xmin::test::with_dialog_answer $top.apropos Apropos \
|
||||
::mged::gui::test::with_dialog_answer $top.apropos Apropos \
|
||||
$top.apropos.mid.ent view $top.apropos.bot.button0 \
|
||||
[list ::mged::xmin::test::invoke $top {Help Apropos}]
|
||||
[list ::mged::gui::test::invoke $top {Help Apropos}]
|
||||
set help_window $top.help
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $help_window] && [winfo ismapped $help_window] &&
|
||||
[$help_window.l size] > 0
|
||||
} "Apropos did not display matching MGED commands"
|
||||
$help_window.l selection set 0
|
||||
focus $help_window.l
|
||||
::mged::xmin::test::with_dialog_answer .mged_dialog Usage "" "" \
|
||||
::mged::gui::test::with_dialog_answer .mged_dialog Usage "" "" \
|
||||
.mged_dialog.bot.button0 \
|
||||
[list event generate $help_window.l <KeyPress> -keysym Return]
|
||||
$help_window.cancel invoke
|
||||
::xmin::test::require {![winfo exists $help_window]} \
|
||||
::gui::test::require {![winfo exists $help_window]} \
|
||||
"Apropos results did not dismiss"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::help::exercise_static_help {id top} {
|
||||
::mged::xmin::test::with_dialog_answer .mged_dialog {Shift Grips} \
|
||||
::mged::gui::test::with_dialog_answer .mged_dialog {Shift Grips} \
|
||||
"" "" .mged_dialog.bot.button0 \
|
||||
[list ::mged::xmin::test::invoke $top {Help {Shift Grips}}]
|
||||
[list ::mged::gui::test::invoke $top {Help {Shift Grips}}]
|
||||
|
||||
::mged::xmin::test::invoke $top {Help Dedication}
|
||||
::mged::gui::test::invoke $top {Help Dedication}
|
||||
set dedication .$id\_mike
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $dedication] && [winfo ismapped $dedication] &&
|
||||
[wm title $dedication] eq "Dedication" &&
|
||||
[string first "Michael John Muuss" [$dedication.dates cget -text]] >= 0
|
||||
} "Dedication did not display its expected content"
|
||||
$dedication.dismiss invoke
|
||||
::xmin::test::require {![winfo exists $dedication]} \
|
||||
::gui::test::require {![winfo exists $dedication]} \
|
||||
"Dedication did not dismiss"
|
||||
}
|
||||
|
||||
@@ -128,7 +140,7 @@ proc ::mged::xmin::help::exercise_html_manual {top} {
|
||||
variable exec_arguments
|
||||
|
||||
set manual_path [file normalize [file join $mged_html_dir index.html]]
|
||||
::xmin::test::require {[file readable $manual_path]} \
|
||||
::gui::test::require {[file readable $manual_path]} \
|
||||
"built MGED HTML manual is unavailable"
|
||||
|
||||
set browser [auto_execok true]
|
||||
@@ -137,24 +149,52 @@ proc ::mged::xmin::help::exercise_html_manual {top} {
|
||||
rename ::exec ::mged::xmin::help::saved_exec
|
||||
rename ::mged::xmin::help::record_exec ::exec
|
||||
set status [catch {
|
||||
::mged::xmin::test::invoke $top {Help Manual}
|
||||
::mged::gui::test::invoke $top {Help Manual}
|
||||
} message options]
|
||||
rename ::exec ::mged::xmin::help::record_exec
|
||||
rename ::mged::xmin::help::saved_exec ::exec
|
||||
if {$status} {
|
||||
return -options $options $message
|
||||
}
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
$exec_arguments eq [list -- {*}$browser $manual_path &]
|
||||
} "Manual did not dispatch the configured browser with its index page"
|
||||
|
||||
set mged_browser [file join $::env(XMIN_TEST_DIR) missing-browser]
|
||||
::mged::xmin::test::invoke $top {Help Manual}
|
||||
set mged_browser [file join $::env(GUI_TEST_DIR) missing-browser]
|
||||
::mged::gui::test::invoke $top {Help Manual}
|
||||
set fallback $top.man
|
||||
::xmin::test::require {
|
||||
set viewer $fallback.html
|
||||
::gui::test::require {
|
||||
[winfo exists $fallback] && [winfo ismapped $fallback] &&
|
||||
[string length [string trim [$fallback.text get 1.0 end]]] > 100
|
||||
[winfo exists $viewer] && [$viewer title] eq "Table of Contents"
|
||||
} "Manual did not load MGED's internal HTML viewer"
|
||||
|
||||
set special_path [file join [pwd] {manual path} {contents#1.html}]
|
||||
::gui::test::require {
|
||||
[::mged::manual::local_path \
|
||||
[::mged::manual::file_uri $special_path]] eq \
|
||||
[file normalize $special_path]
|
||||
} "internal Manual viewer did not preserve special path characters"
|
||||
|
||||
set html [$viewer html]
|
||||
set contents [$html text text]
|
||||
::gui::test::require {
|
||||
[string first "Preface" $contents] >= 0 &&
|
||||
[string first "background-color" $contents] < 0
|
||||
} "internal Manual viewer did not render its table of contents"
|
||||
|
||||
$viewer goto mged.html#csg
|
||||
::mged::gui::test::settle
|
||||
set contents [$html text text]
|
||||
::gui::test::require {
|
||||
[$viewer title] eq "Mged User's Manual" &&
|
||||
[string first "Modeling With CSG" $contents] >= 0
|
||||
} "internal Manual viewer did not follow its document links"
|
||||
|
||||
$fallback.f.back invoke
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {[$viewer title] eq "Table of Contents"} \
|
||||
"internal Manual viewer Back button did not restore the prior page"
|
||||
destroy $fallback
|
||||
}
|
||||
|
||||
@@ -166,7 +206,7 @@ proc ::mged::xmin::help::run {id top} {
|
||||
exercise_html_manual $top
|
||||
}
|
||||
|
||||
::mged::xmin::test::start ::mged::xmin::help::run \
|
||||
::mged::gui::test::start ::mged::xmin::help::run \
|
||||
{MGED manual and help lookup} {MGED help regression}
|
||||
|
||||
# Local Variables:
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
###
|
||||
# Exercise the MGED LOD Configuration dialog and its CSG/VDS render paths.
|
||||
|
||||
source $::env(MGED_XMIN_GUI_LIBRARY)
|
||||
source $::env(MGED_GUI_TEST_LIBRARY)
|
||||
|
||||
namespace eval ::mged::xmin::lod {
|
||||
variable dense_point_scale 1.5
|
||||
@@ -33,7 +33,7 @@ proc ::mged::xmin::lod::require_near {actual expected description} {
|
||||
variable tolerance
|
||||
if {![string is double -strict $actual] ||
|
||||
abs($actual - $expected) > $tolerance} {
|
||||
::mged::xmin::test::fail \
|
||||
::mged::gui::test::fail \
|
||||
"$description is '$actual', expected '$expected'"
|
||||
}
|
||||
}
|
||||
@@ -69,10 +69,10 @@ proc ::mged::xmin::lod::create_adaptive_bot {name} {
|
||||
}
|
||||
|
||||
proc ::mged::xmin::lod::plot_segment_count {tag} {
|
||||
set plot_path [file join $::env(XMIN_TEST_DIR) "$tag.plot3"]
|
||||
set plot_path [file join $::env(GUI_TEST_DIR) "$tag.plot3"]
|
||||
file delete -force $plot_path
|
||||
_mged_plot $plot_path
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[file exists $plot_path] && [file size $plot_path] > 0
|
||||
} "LOD $tag plot was not produced"
|
||||
|
||||
@@ -85,21 +85,21 @@ proc ::mged::xmin::lod::exercise_dialog {top} {
|
||||
lod scale points 0.6
|
||||
lod scale curves 7
|
||||
|
||||
::mged::xmin::test::invoke $top {Tools {LOD Configuration}}
|
||||
::mged::gui::test::invoke $top {Tools {LOD Configuration}}
|
||||
set dialog .loddialog
|
||||
set contents $dialog.contents
|
||||
set frame $contents.lodFrame
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $dialog] && [winfo ismapped $dialog]
|
||||
} "LOD Configuration did not open"
|
||||
::xmin::test::require {[wm title $dialog] eq "LOD Configuration"} \
|
||||
::gui::test::require {[wm title $dialog] eq "LOD Configuration"} \
|
||||
"LOD Configuration has an unexpected title"
|
||||
|
||||
require_near [$frame.pointsScale get] 0.6 \
|
||||
"LOD point scale initial widget value"
|
||||
require_near [$frame.curvesScale get] 7 \
|
||||
"LOD curve scale initial widget value"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lod enabled] == 0 &&
|
||||
[$frame.pointsScale instate disabled] &&
|
||||
[$frame.pointsValueLabel instate disabled] &&
|
||||
@@ -109,8 +109,8 @@ proc ::mged::xmin::lod::exercise_dialog {top} {
|
||||
} "disabled LOD state was not reflected by every dependent widget"
|
||||
|
||||
$frame.lodonCheckbutton invoke
|
||||
::mged::xmin::test::settle
|
||||
::xmin::test::require {
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {
|
||||
[lod enabled] == 1 &&
|
||||
![$frame.pointsScale instate disabled] &&
|
||||
![$frame.curvesScale instate disabled] &&
|
||||
@@ -119,22 +119,22 @@ proc ::mged::xmin::lod::exercise_dialog {top} {
|
||||
|
||||
$frame.pointsScale set 1.3
|
||||
$frame.curvesScale set 11
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
require_near [lod scale points] 1.3 "LOD point scale command value"
|
||||
require_near [lod scale curves] 11 "LOD curve scale command value"
|
||||
|
||||
$frame.liveUpdateCheckbutton invoke
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$frame.liveUpdateCheckbutton instate selected]
|
||||
} "LOD Live Update control did not select"
|
||||
$frame.pointsScale set 0.8
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
require_near [lod scale points] 0.8 "live LOD point scale value"
|
||||
|
||||
$frame.updateButton invoke
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
destroy $dialog
|
||||
::xmin::test::require {![winfo exists $dialog]} \
|
||||
::gui::test::require {![winfo exists $dialog]} \
|
||||
"LOD Configuration did not close"
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ proc ::mged::xmin::lod::exercise_render_paths {} {
|
||||
|
||||
make xmin_lod_ell.s ell
|
||||
set face_count [create_adaptive_bot xmin_lod_bot.s]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[exists xmin_lod_bot.s] && [lindex [get xmin_lod_bot.s] 0] eq "bot"
|
||||
} "LOD fixture did not produce a BoT"
|
||||
|
||||
@@ -169,7 +169,7 @@ proc ::mged::xmin::lod::exercise_render_paths {} {
|
||||
refresh
|
||||
set dense_segments [expr {[plot_segment_count dense-detail] - $background_segments}]
|
||||
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
$full_segments == $face_count * 3 &&
|
||||
$sparse_segments > 0 &&
|
||||
$sparse_segments < $dense_segments &&
|
||||
@@ -178,7 +178,7 @@ proc ::mged::xmin::lod::exercise_render_paths {} {
|
||||
|
||||
draw xmin_lod_ell.s
|
||||
refresh
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lod enabled] == 1 &&
|
||||
[lsearch -exact [who] xmin_lod_ell.s] >= 0
|
||||
} "adaptive CSG drawing did not remain active"
|
||||
@@ -189,8 +189,8 @@ proc ::mged::xmin::lod::exercise_render_paths {} {
|
||||
}
|
||||
|
||||
proc ::mged::xmin::lod::run {id top} {
|
||||
set database [file join $::env(XMIN_TEST_DIR) lod.g]
|
||||
cd $::env(XMIN_TEST_DIR)
|
||||
set database [file join $::env(GUI_TEST_DIR) lod.g]
|
||||
cd $::env(GUI_TEST_DIR)
|
||||
file delete -force $database
|
||||
opendb $database y
|
||||
title {Xmin MGED LOD regression}
|
||||
@@ -199,7 +199,7 @@ proc ::mged::xmin::lod::run {id top} {
|
||||
exercise_dialog $top
|
||||
}
|
||||
|
||||
::mged::xmin::test::start ::mged::xmin::lod::run \
|
||||
::mged::gui::test::start ::mged::xmin::lod::run \
|
||||
{MGED LOD dialog and adaptive rendering} \
|
||||
{MGED LOD regression}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
###
|
||||
# Exercise MGED's overlap-generation workflow through live widgets.
|
||||
|
||||
source $::env(MGED_XMIN_GUI_LIBRARY)
|
||||
source $::env(MGED_GUI_TEST_LIBRARY)
|
||||
|
||||
namespace eval ::mged::xmin::overlaps {}
|
||||
|
||||
@@ -43,51 +43,51 @@ proc ::mged::xmin::overlaps::exercise_overlap_tool {top database} {
|
||||
make_overlap_group second 100
|
||||
Z
|
||||
|
||||
::mged::xmin::test::invoke $top {Tools {Overlaps Tool}}
|
||||
::mged::gui::test::invoke $top {Tools {Overlaps Tool}}
|
||||
set menu .overlapmenu.overlapmenu
|
||||
::mged::xmin::test::require_mapped $menu "Overlap Menu"
|
||||
::mged::gui::test::require_mapped $menu "Overlap Menu"
|
||||
$menu.buttonsFrame.newFileFrame.buttonRunOvFileGen invoke
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
|
||||
set tool .overlapmenu.overlapfiletool.overlapfiletool
|
||||
::mged::xmin::test::require_mapped $tool "Overlap File Tool"
|
||||
::mged::gui::test::require_mapped $tool "Overlap File Tool"
|
||||
$tool clearSelection
|
||||
::mged::xmin::test::set_entry $tool.ovFrame.objectsEntry \
|
||||
::mged::gui::test::set_entry $tool.ovFrame.objectsEntry \
|
||||
{first.g second.g}
|
||||
$tool.ovFrame.buttonAdd invoke
|
||||
set selected [$tool.objFrame.objectsList get 0 end]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength $selected] == 2 &&
|
||||
[lsearch -glob $selected */first.g] >= 0 &&
|
||||
[lsearch -glob $selected */second.g] >= 0
|
||||
} "Overlap File Tool did not retain two separately selected objects"
|
||||
|
||||
$tool.ovButtonFrame.buttonGo invoke
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
|
||||
set checker .checker.ck
|
||||
::mged::xmin::test::require_mapped $checker "Geometry Checker"
|
||||
::mged::gui::test::require_mapped $checker "Geometry Checker"
|
||||
set tree $checker.checkFrame.checkList
|
||||
set rows [$tree children {}]
|
||||
::xmin::test::require {[llength $rows] == 2} \
|
||||
::gui::test::require {[llength $rows] == 2} \
|
||||
"generated overlap file did not contain both selected assemblies"
|
||||
|
||||
$checker.headerFrame.fullPathDisplayCheckButton invoke
|
||||
set first_row [lindex $rows 0]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string index [$tree set $first_row Left] 0] eq "/" &&
|
||||
[string index [$tree set $first_row Right] 0] eq "/"
|
||||
} "Geometry Checker did not display full paths"
|
||||
|
||||
$tree selection set $first_row
|
||||
event generate $tree <<TreeviewSelect>>
|
||||
::mged::xmin::test::settle
|
||||
::xmin::test::require {[llength [who]] >= 2} \
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {[llength [who]] >= 2} \
|
||||
"selecting an overlap did not draw its objects"
|
||||
|
||||
$tree.checkMenu invoke 2
|
||||
set copied [clipboard get]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string first "/" $copied] >= 0 && [llength $copied] == 2
|
||||
} "Geometry Checker did not copy both full paths"
|
||||
|
||||
@@ -98,26 +98,26 @@ proc ::mged::xmin::overlaps::exercise_overlap_tool {top database} {
|
||||
|
||||
set mark_file [file join "${database}.ck" \
|
||||
"ck.[file tail $database].marked"]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[file exists $mark_file] && [$tree tag has marked $first_row]
|
||||
} "Geometry Checker did not persist a resolved mark"
|
||||
set mark_channel [open $mark_file r]
|
||||
set marked_paths [gets $mark_channel]
|
||||
close $mark_channel
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength $marked_paths] == 2
|
||||
} "Geometry Checker did not write both marked overlap paths"
|
||||
|
||||
$tree selection set $first_row
|
||||
$tree.checkMenu invoke 1
|
||||
::xmin::test::require {![$tree tag has marked $first_row]} \
|
||||
::gui::test::require {![$tree tag has marked $first_row]} \
|
||||
"Geometry Checker did not clear a resolved mark"
|
||||
destroy .checker
|
||||
}
|
||||
|
||||
proc ::mged::xmin::overlaps::run {id top} {
|
||||
set database [file join $::env(XMIN_TEST_DIR) overlaps.g]
|
||||
cd $::env(XMIN_TEST_DIR)
|
||||
set database [file join $::env(GUI_TEST_DIR) overlaps.g]
|
||||
cd $::env(GUI_TEST_DIR)
|
||||
file delete -force $database "${database}.ck"
|
||||
opendb $database y
|
||||
title {Xmin MGED overlap regression}
|
||||
@@ -125,7 +125,7 @@ proc ::mged::xmin::overlaps::run {id top} {
|
||||
exercise_overlap_tool $top $database
|
||||
}
|
||||
|
||||
::mged::xmin::test::start ::mged::xmin::overlaps::run \
|
||||
::mged::gui::test::start ::mged::xmin::overlaps::run \
|
||||
{MGED overlap tools} {MGED overlap regression}
|
||||
|
||||
# Local Variables:
|
||||
|
||||
@@ -20,22 +20,22 @@
|
||||
###
|
||||
# Exercise MGED's Query Ray and Build Pattern tools through live widgets.
|
||||
|
||||
source $::env(MGED_XMIN_GUI_LIBRARY)
|
||||
source $::env(MGED_GUI_TEST_LIBRARY)
|
||||
|
||||
namespace eval ::mged::xmin::query_pattern {}
|
||||
|
||||
proc ::mged::xmin::query_pattern::set_components {dialog values} {
|
||||
foreach {component value} $values {
|
||||
::mged::xmin::test::set_entry $dialog.$component $value
|
||||
::mged::gui::test::set_entry $dialog.$component $value
|
||||
}
|
||||
}
|
||||
|
||||
proc ::mged::xmin::query_pattern::require_pattern {
|
||||
group first_clone second_clone description
|
||||
} {
|
||||
::xmin::test::require {[exists $group]} "$description group was not created"
|
||||
::gui::test::require {[exists $group]} "$description group was not created"
|
||||
set definition [get $group]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string first $first_clone $definition] >= 0 &&
|
||||
[string first $second_clone $definition] >= 0
|
||||
} "$description group did not contain both requested clones"
|
||||
@@ -50,21 +50,21 @@ proc ::mged::xmin::query_pattern::exercise_query_ray {id top} {
|
||||
qray effects t
|
||||
qray basename query_ray
|
||||
|
||||
::mged::xmin::test::invoke $top {Tools {Query Ray Control Panel}}
|
||||
::mged::gui::test::invoke $top {Tools {Query Ray Control Panel}}
|
||||
set dialog .$id.qray_control
|
||||
::mged::xmin::test::require_mapped $dialog "Query Ray Control Panel"
|
||||
::mged::gui::test::require_mapped $dialog "Query Ray Control Panel"
|
||||
|
||||
$dialog.activeCB invoke
|
||||
$dialog.use_airCB invoke
|
||||
$dialog.cmd_echoCB invoke
|
||||
$dialog.effectsMB.m invoke 2
|
||||
::mged::xmin::test::set_entry $dialog.bnameE xmin_qray
|
||||
::mged::gui::test::set_entry $dialog.bnameE xmin_qray
|
||||
set qray_control($id,oddcolor) {12 34 56}
|
||||
color_entry_update $dialog oddColor qray_control($id,oddcolor) \
|
||||
$qray_control($id,oddcolor)
|
||||
$dialog.applyB invoke
|
||||
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
$mouse_behavior eq "q" &&
|
||||
$use_air == 1 &&
|
||||
[_mged_qray echo] == 1 &&
|
||||
@@ -74,31 +74,31 @@ proc ::mged::xmin::query_pattern::exercise_query_ray {id top} {
|
||||
} "Query Ray Apply did not persist mouse, air, effect, name, or color settings"
|
||||
|
||||
$dialog.advB invoke
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
set advanced .$id.qray_adv
|
||||
::mged::xmin::test::require_mapped $advanced \
|
||||
::mged::gui::test::require_mapped $advanced \
|
||||
"Query Ray Advanced Settings"
|
||||
|
||||
set applied_format {XMIN RAY FORMAT}
|
||||
::mged::xmin::test::set_entry $advanced.rayE $applied_format
|
||||
::mged::gui::test::set_entry $advanced.rayE $applied_format
|
||||
$advanced.applyB invoke
|
||||
::xmin::test::require {[_mged_qray fmt r] eq $applied_format} \
|
||||
::gui::test::require {[_mged_qray fmt r] eq $applied_format} \
|
||||
"Query Ray advanced Apply did not persist the ray format"
|
||||
|
||||
::mged::xmin::test::set_entry $advanced.rayE {discarded format}
|
||||
::mged::gui::test::set_entry $advanced.rayE {discarded format}
|
||||
$advanced.resetB invoke
|
||||
::xmin::test::require {$qray_control($id,fmt_ray) eq $applied_format} \
|
||||
::gui::test::require {$qray_control($id,fmt_ray) eq $applied_format} \
|
||||
"Query Ray advanced Reset did not restore the applied format"
|
||||
$advanced.okB invoke
|
||||
::xmin::test::require {![winfo exists $advanced]} \
|
||||
::gui::test::require {![winfo exists $advanced]} \
|
||||
"Query Ray Advanced Settings did not close after OK"
|
||||
|
||||
::mged::xmin::test::set_entry $dialog.bnameE discarded_name
|
||||
::mged::gui::test::set_entry $dialog.bnameE discarded_name
|
||||
$dialog.resetB invoke
|
||||
::xmin::test::require {$qray_control($id,basename) eq "xmin_qray"} \
|
||||
::gui::test::require {$qray_control($id,basename) eq "xmin_qray"} \
|
||||
"Query Ray Reset did not restore the applied base name"
|
||||
$dialog.okB invoke
|
||||
::xmin::test::require {![winfo exists $dialog]} \
|
||||
::gui::test::require {![winfo exists $dialog]} \
|
||||
"Query Ray Control Panel did not close after OK"
|
||||
}
|
||||
|
||||
@@ -107,9 +107,9 @@ proc ::mged::xmin::query_pattern::exercise_patterns {top} {
|
||||
make sph_source.s sph
|
||||
make cyl_source.s sph
|
||||
|
||||
::mged::xmin::test::invoke $top {Tools {Build Pattern Tool}}
|
||||
set dialog [::mged::xmin::test::find_toplevel_by_title "Pattern Control"]
|
||||
::mged::xmin::test::require_mapped $dialog "Build Pattern Tool"
|
||||
::mged::gui::test::invoke $top {Tools {Build Pattern Tool}}
|
||||
set dialog [::mged::gui::test::find_toplevel_by_title "Pattern Control"]
|
||||
::mged::gui::test::require_mapped $dialog "Build Pattern Tool"
|
||||
|
||||
set_components $dialog {
|
||||
e_group_r rect_pattern.g
|
||||
@@ -167,13 +167,13 @@ proc ::mged::xmin::query_pattern::exercise_patterns {top} {
|
||||
"cylindrical pattern"
|
||||
|
||||
$dialog.b_dismiss_c invoke
|
||||
::xmin::test::require {![winfo exists $dialog]} \
|
||||
::gui::test::require {![winfo exists $dialog]} \
|
||||
"Build Pattern Tool did not dismiss"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::query_pattern::run {id top} {
|
||||
set database [file join $::env(XMIN_TEST_DIR) query-pattern.g]
|
||||
cd $::env(XMIN_TEST_DIR)
|
||||
set database [file join $::env(GUI_TEST_DIR) query-pattern.g]
|
||||
cd $::env(GUI_TEST_DIR)
|
||||
file delete -force $database
|
||||
opendb $database y
|
||||
title {Xmin MGED specialized-tool regression}
|
||||
@@ -187,7 +187,7 @@ proc ::mged::xmin::query_pattern::run {id top} {
|
||||
exercise_patterns $top
|
||||
}
|
||||
|
||||
::mged::xmin::test::start ::mged::xmin::query_pattern::run \
|
||||
::mged::gui::test::start ::mged::xmin::query_pattern::run \
|
||||
{MGED Query Ray and Build Pattern tools} \
|
||||
{MGED Query Ray/Build Pattern regression}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
###
|
||||
# Exercise MGED's Render View output dialogs through their live controls.
|
||||
|
||||
source $::env(MGED_XMIN_GUI_LIBRARY)
|
||||
source $::env(MGED_GUI_TEST_LIBRARY)
|
||||
|
||||
namespace eval ::mged::xmin::render {
|
||||
variable raytrace_image_size 32
|
||||
@@ -36,7 +36,7 @@ proc ::mged::xmin::render::read_file {path {translation auto}} {
|
||||
}
|
||||
|
||||
proc ::mged::xmin::render::require_file {path description} {
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[file exists $path] && [file size $path] > 0
|
||||
} "$description did not produce a nonempty file"
|
||||
}
|
||||
@@ -55,17 +55,17 @@ proc ::mged::xmin::render::wait_for_file_size {path minimum_size timeout_ms} {
|
||||
if {[file exists $path]} {
|
||||
set actual_size [file size $path]
|
||||
}
|
||||
::mged::xmin::test::fail \
|
||||
::mged::gui::test::fail \
|
||||
"raytrace output has $actual_size bytes, expected at least $minimum_size"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::render::exercise_rt_script {id top} {
|
||||
global rts_control
|
||||
|
||||
set output [file join $::env(XMIN_TEST_DIR) saved-view.sh]
|
||||
::mged::xmin::test::invoke $top {File {Render View} {RT Script...}}
|
||||
set output [file join $::env(GUI_TEST_DIR) saved-view.sh]
|
||||
::mged::gui::test::invoke $top {File {Render View} {RT Script...}}
|
||||
set dialog .$id.do_rtScript
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $dialog] && [winfo ismapped $dialog] &&
|
||||
[wm title $dialog] eq "RT Script Tool"
|
||||
} "RT Script did not open its tool"
|
||||
@@ -73,33 +73,33 @@ proc ::mged::xmin::render::exercise_rt_script {id top} {
|
||||
set rts_control($id,file) $output
|
||||
set rts_control($id,args) {-A 0.25}
|
||||
$dialog.createB invoke
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
require_file $output "RT Script"
|
||||
set contents [read_file $output]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string first "-A 0.25" $contents] >= 0 &&
|
||||
[string first "xmin_render.r" $contents] >= 0
|
||||
} "RT Script omitted its requested options or displayed object"
|
||||
set initial_size [file size $output]
|
||||
|
||||
::mged::xmin::test::with_dialog_answer .mged_dialog \
|
||||
::mged::gui::test::with_dialog_answer .mged_dialog \
|
||||
"Append $output?" "" "" .mged_dialog.bot.button0 \
|
||||
[list $dialog.createB invoke]
|
||||
::xmin::test::require {[file size $output] > $initial_size} \
|
||||
::gui::test::require {[file size $output] > $initial_size} \
|
||||
"RT Script overwrite confirmation did not append another view"
|
||||
|
||||
$dialog.dismissB invoke
|
||||
::xmin::test::require {![winfo exists $dialog]} \
|
||||
::gui::test::require {![winfo exists $dialog]} \
|
||||
"RT Script tool did not dismiss"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::render::exercise_plot {id top} {
|
||||
global pl_control
|
||||
|
||||
set output [file join $::env(XMIN_TEST_DIR) rendered.plot3]
|
||||
::mged::xmin::test::invoke $top {File {Render View} {Plot...}}
|
||||
set output [file join $::env(GUI_TEST_DIR) rendered.plot3]
|
||||
::mged::gui::test::invoke $top {File {Render View} {Plot...}}
|
||||
set dialog .$id.do_plot
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $dialog] && [winfo ismapped $dialog]
|
||||
} "Plot did not open its tool"
|
||||
|
||||
@@ -108,37 +108,37 @@ proc ::mged::xmin::render::exercise_plot {id top} {
|
||||
set pl_control($id,2d) 0
|
||||
set pl_control($id,float) 0
|
||||
$dialog.createB invoke
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
require_file $output "Plot"
|
||||
set plot_text [exec $::env(PLOT3_ASC_BIN) $output]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[regexp -line {^L[ \t]} $plot_text] &&
|
||||
[llength [split $plot_text \n]] > 10
|
||||
} "Plot output could not be decoded into line records"
|
||||
|
||||
$dialog.filterRB invoke
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$dialog.fileE cget -state] eq "disabled" &&
|
||||
[$dialog.filterE cget -state] eq "normal"
|
||||
} "Plot filter selection did not update entry states"
|
||||
$dialog.fileRB invoke
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[$dialog.fileE cget -state] eq "normal" &&
|
||||
[$dialog.filterE cget -state] eq "disabled"
|
||||
} "Plot file selection did not restore entry states"
|
||||
|
||||
$dialog.dismissB invoke
|
||||
::xmin::test::require {![winfo exists $dialog]} \
|
||||
::gui::test::require {![winfo exists $dialog]} \
|
||||
"Plot tool did not dismiss"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::render::exercise_postscript {id top} {
|
||||
global ps_control
|
||||
|
||||
set output [file join $::env(XMIN_TEST_DIR) rendered.ps]
|
||||
::mged::xmin::test::invoke $top {File {Render View} {PostScript...}}
|
||||
set output [file join $::env(GUI_TEST_DIR) rendered.ps]
|
||||
::mged::gui::test::invoke $top {File {Render View} {PostScript...}}
|
||||
set dialog .$id.do_ps
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $dialog] && [winfo ismapped $dialog]
|
||||
} "PostScript did not open its tool"
|
||||
|
||||
@@ -149,14 +149,14 @@ proc ::mged::xmin::render::exercise_postscript {id top} {
|
||||
set ps_control($id,linewidth) 2
|
||||
set ps_control($id,zclip) 1
|
||||
$dialog.fontMB.fontM.helveticaM invoke Bold
|
||||
::xmin::test::require {$ps_control($id,font) eq "Helvetica-Bold"} \
|
||||
::gui::test::require {$ps_control($id,font) eq "Helvetica-Bold"} \
|
||||
"PostScript font menu did not update the selected font"
|
||||
|
||||
$dialog.createB invoke
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
require_file $output "PostScript"
|
||||
set contents [read_file $output]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string first "%!PS-Adobe" $contents] == 0 &&
|
||||
[string first "Xmin Render Output" $contents] >= 0 &&
|
||||
[string first "MGED regression" $contents] >= 0 &&
|
||||
@@ -164,7 +164,7 @@ proc ::mged::xmin::render::exercise_postscript {id top} {
|
||||
} "PostScript output omitted its header or configured metadata"
|
||||
|
||||
$dialog.dismissB invoke
|
||||
::xmin::test::require {![winfo exists $dialog]} \
|
||||
::gui::test::require {![winfo exists $dialog]} \
|
||||
"PostScript tool did not dismiss"
|
||||
}
|
||||
|
||||
@@ -173,10 +173,10 @@ proc ::mged::xmin::render::exercise_raytrace {id top} {
|
||||
variable raytrace_image_size
|
||||
variable raytrace_timeout_ms
|
||||
|
||||
set output [file join $::env(XMIN_TEST_DIR) rendered.pix]
|
||||
::mged::xmin::test::invoke $top {File Raytrace}
|
||||
set output [file join $::env(GUI_TEST_DIR) rendered.pix]
|
||||
::mged::gui::test::invoke $top {File Raytrace}
|
||||
set dialog .$id.rt
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $dialog] && [winfo ismapped $dialog]
|
||||
} "File > Raytrace did not open the Raytrace Control Panel"
|
||||
|
||||
@@ -197,13 +197,13 @@ proc ::mged::xmin::render::exercise_raytrace {id top} {
|
||||
$raytrace_timeout_ms
|
||||
|
||||
$dialog.dismissB invoke
|
||||
::xmin::test::require {![winfo exists $dialog]} \
|
||||
::gui::test::require {![winfo exists $dialog]} \
|
||||
"Raytrace Control Panel did not dismiss"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::render::run {id top} {
|
||||
set database [file join $::env(XMIN_TEST_DIR) render.g]
|
||||
cd $::env(XMIN_TEST_DIR)
|
||||
set database [file join $::env(GUI_TEST_DIR) render.g]
|
||||
cd $::env(GUI_TEST_DIR)
|
||||
file delete -force $database
|
||||
opendb $database y
|
||||
title {Xmin MGED render-output regression}
|
||||
@@ -220,7 +220,7 @@ proc ::mged::xmin::render::run {id top} {
|
||||
exercise_raytrace $id $top
|
||||
}
|
||||
|
||||
::mged::xmin::test::start ::mged::xmin::render::run \
|
||||
::mged::gui::test::start ::mged::xmin::render::run \
|
||||
{MGED Render View output dialogs} {MGED render-output regression}
|
||||
|
||||
# Local Variables:
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
###
|
||||
# Exercise asynchronous search -exec drawing, serialization, and interruption.
|
||||
|
||||
if {![info exists ::env(XMIN_GUI_LIBRARY)] ||
|
||||
![info exists ::env(XMIN_TEST_DIR)]} {
|
||||
puts stderr "XMIN_GUI_LIBRARY and XMIN_TEST_DIR are required"
|
||||
if {![info exists ::env(GUI_TEST_LIBRARY)] ||
|
||||
![info exists ::env(GUI_TEST_DIR)]} {
|
||||
puts stderr "GUI_TEST_LIBRARY and GUI_TEST_DIR are required"
|
||||
exit 2
|
||||
}
|
||||
source $::env(XMIN_GUI_LIBRARY)
|
||||
::xmin::test::capture_background_errors
|
||||
source $::env(GUI_TEST_LIBRARY)
|
||||
::gui::test::capture_background_errors
|
||||
|
||||
namespace eval ::mged::xmin::search_exec {
|
||||
variable command_widget ""
|
||||
@@ -85,7 +85,7 @@ proc ::mged::xmin::search_exec::exercise {} {
|
||||
variable nested_status
|
||||
|
||||
set paths [_mged_search / -type tgc]
|
||||
::xmin::test::require {[llength $paths] >= $minimum_tgc_paths} \
|
||||
::gui::test::require {[llength $paths] >= $minimum_tgc_paths} \
|
||||
"m35.g supplied too few TGC paths for the scaling regression"
|
||||
|
||||
set nested_done 0
|
||||
@@ -99,11 +99,11 @@ proc ::mged::xmin::search_exec::exercise {} {
|
||||
} draw_message]
|
||||
set draw_elapsed [expr {[clock milliseconds] - $started}]
|
||||
|
||||
::xmin::test::require {$draw_status == 0} \
|
||||
::gui::test::require {$draw_status == 0} \
|
||||
"search -exec draw failed: $draw_message"
|
||||
::xmin::test::require {$nested_done} \
|
||||
::gui::test::require {$nested_done} \
|
||||
"the event loop did not service the nested search probe"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
$nested_status == 1 &&
|
||||
$nested_message eq "another MGED command is already running" &&
|
||||
$nested_error_code eq {BRLCAD MGED COMMAND_BUSY}
|
||||
@@ -111,9 +111,9 @@ proc ::mged::xmin::search_exec::exercise {} {
|
||||
set draw_limit_message [format \
|
||||
"search -exec draw took %dms; expected less than %dms" \
|
||||
$draw_elapsed $draw_time_limit_ms]
|
||||
::xmin::test::require {$draw_elapsed < $draw_time_limit_ms} \
|
||||
::gui::test::require {$draw_elapsed < $draw_time_limit_ms} \
|
||||
$draw_limit_message
|
||||
::xmin::test::require {[llength [_mged_who]] >= $minimum_tgc_paths} \
|
||||
::gui::test::require {[llength [_mged_who]] >= $minimum_tgc_paths} \
|
||||
"search -exec draw did not populate the display list"
|
||||
|
||||
set redraw_started [clock milliseconds]
|
||||
@@ -121,12 +121,12 @@ proc ::mged::xmin::search_exec::exercise {} {
|
||||
_mged_search / -type tgc -exec draw "{}" ";"
|
||||
} redraw_message]
|
||||
set redraw_elapsed [expr {[clock milliseconds] - $redraw_started}]
|
||||
::xmin::test::require {$redraw_status == 0} \
|
||||
::gui::test::require {$redraw_status == 0} \
|
||||
"repeated search -exec draw failed: $redraw_message"
|
||||
set redraw_limit_message [format \
|
||||
"repeated search -exec draw took %dms; expected less than %dms" \
|
||||
$redraw_elapsed $draw_time_limit_ms]
|
||||
::xmin::test::require {$redraw_elapsed < $draw_time_limit_ms} \
|
||||
::gui::test::require {$redraw_elapsed < $draw_time_limit_ms} \
|
||||
$redraw_limit_message
|
||||
|
||||
_mged_Z
|
||||
@@ -136,9 +136,9 @@ proc ::mged::xmin::search_exec::exercise {} {
|
||||
_mged_search / -type tgc -exec draw "{}" ";"
|
||||
} interrupt_message]
|
||||
|
||||
::xmin::test::require {$interrupt_requested == 1} \
|
||||
::gui::test::require {$interrupt_requested == 1} \
|
||||
"the running search did not accept an interrupt request"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
$interrupt_status == 1 && $interrupt_message eq "Command interrupted."
|
||||
} "interrupted search returned an unexpected result: $interrupt_message"
|
||||
|
||||
@@ -148,14 +148,14 @@ proc ::mged::xmin::search_exec::exercise {} {
|
||||
set followup_status [catch {
|
||||
_mged_search $followup_path -type tgc -exec ls "{}" ";"
|
||||
} followup_message]
|
||||
::xmin::test::require {$followup_status == 0} \
|
||||
::gui::test::require {$followup_status == 0} \
|
||||
"search -exec failed after interruption: $followup_message"
|
||||
|
||||
_mged_Z
|
||||
_mged_draw $ancestor
|
||||
set ancestor_display [_mged_who]
|
||||
_mged_draw $followup_path
|
||||
::xmin::test::require {[_mged_who] eq $ancestor_display} \
|
||||
::gui::test::require {[_mged_who] eq $ancestor_display} \
|
||||
"drawing a child path duplicated its displayed ancestor"
|
||||
|
||||
_mged_Z
|
||||
@@ -163,13 +163,13 @@ proc ::mged::xmin::search_exec::exercise {} {
|
||||
_mged_draw [lindex $paths 1]
|
||||
_mged_draw $ancestor
|
||||
set consolidated_display [_mged_who]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength $consolidated_display] == 1 &&
|
||||
[lindex $consolidated_display 0] eq $ancestor
|
||||
} "drawing an ancestor did not replace its displayed descendants"
|
||||
|
||||
set component_paths [_mged_search /component -type tgc]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength $component_paths] >= $minimum_tgc_paths
|
||||
} "component supplied too few TGC paths for the overlap regression"
|
||||
|
||||
@@ -180,15 +180,15 @@ proc ::mged::xmin::search_exec::exercise {} {
|
||||
_mged_search /component -type tgc -exec draw "{}" ";"
|
||||
} covered_message]
|
||||
set covered_elapsed [expr {[clock milliseconds] - $covered_started}]
|
||||
::xmin::test::require {$covered_status == 0} \
|
||||
::gui::test::require {$covered_status == 0} \
|
||||
"drawing paths under component failed: $covered_message"
|
||||
set covered_limit_message [format \
|
||||
"drawing paths under component took %dms; expected less than %dms" \
|
||||
$covered_elapsed $covered_draw_time_limit_ms]
|
||||
::xmin::test::require {$covered_elapsed < $covered_draw_time_limit_ms} \
|
||||
::gui::test::require {$covered_elapsed < $covered_draw_time_limit_ms} \
|
||||
$covered_limit_message
|
||||
set covered_display [_mged_who]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength $covered_display] == 1 &&
|
||||
[lindex $covered_display 0] eq "component"
|
||||
} "drawing covered paths changed the component display root"
|
||||
@@ -198,7 +198,7 @@ proc ::mged::xmin::search_exec::exercise {} {
|
||||
append metrics "\ncovered_elapsed_ms $covered_elapsed"
|
||||
puts "MGED search-exec: [llength $paths] paths, first $draw_elapsed ms, \
|
||||
redraw $redraw_elapsed ms"
|
||||
::xmin::test::write search_exec_metrics $metrics
|
||||
::gui::test::write search_exec_metrics $metrics
|
||||
}
|
||||
|
||||
proc ::mged::xmin::search_exec::finish {status message} {
|
||||
@@ -208,10 +208,10 @@ proc ::mged::xmin::search_exec::finish {status message} {
|
||||
}
|
||||
set finished 1
|
||||
catch {update}
|
||||
lassign [::xmin::test::check_background_errors $status $message] \
|
||||
lassign [::gui::test::check_background_errors $status $message] \
|
||||
status message
|
||||
puts $message
|
||||
::xmin::test::write result $message
|
||||
::gui::test::write result $message
|
||||
if {$status != 0} {
|
||||
puts stderr $message
|
||||
}
|
||||
@@ -265,7 +265,7 @@ proc ::mged::xmin::search_exec::run {} {
|
||||
proc ::mged::xmin::search_exec::run_checked {} {
|
||||
if {[catch {run} message options]} {
|
||||
if {[dict exists $options -errorinfo]} {
|
||||
::xmin::test::write tcl_error_debug [dict get $options -errorinfo]
|
||||
::gui::test::write tcl_error_debug [dict get $options -errorinfo]
|
||||
}
|
||||
finish 1 "FAIL: MGED search -exec regression: $message"
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
###
|
||||
# Exercise ShotVis construction, interactive editing, persistence, and reload.
|
||||
|
||||
source $::env(MGED_XMIN_GUI_LIBRARY)
|
||||
source $::env(MGED_GUI_TEST_LIBRARY)
|
||||
|
||||
namespace eval ::mged::xmin::shotvis {
|
||||
variable basename xmin_shot
|
||||
@@ -31,7 +31,7 @@ proc ::mged::xmin::shotvis::require_near {actual expected description} {
|
||||
variable tolerance
|
||||
if {![string is double -strict $actual] ||
|
||||
abs($actual - $expected) > $tolerance} {
|
||||
::mged::xmin::test::fail \
|
||||
::mged::gui::test::fail \
|
||||
"$description is '$actual', expected '$expected'"
|
||||
}
|
||||
}
|
||||
@@ -39,10 +39,10 @@ proc ::mged::xmin::shotvis::require_near {actual expected description} {
|
||||
proc ::mged::xmin::shotvis::root_combination {} {
|
||||
set title [wm title .shotvis]
|
||||
set prefix {Edit Shotline Visualization - }
|
||||
::xmin::test::require {[string first $prefix $title] == 0} \
|
||||
::gui::test::require {[string first $prefix $title] == 0} \
|
||||
"ShotVis window title does not identify its active root"
|
||||
set root [string range $title [string length $prefix] end]
|
||||
::xmin::test::require {[exists $root]} \
|
||||
::gui::test::require {[exists $root]} \
|
||||
"ShotVis active root '$root' does not exist"
|
||||
return $root
|
||||
}
|
||||
@@ -50,7 +50,7 @@ proc ::mged::xmin::shotvis::root_combination {} {
|
||||
proc ::mged::xmin::shotvis::threat_combination {} {
|
||||
set root [root_combination]
|
||||
set threats [search $root -attr shotvis_threat]
|
||||
::xmin::test::require {[llength $threats] == 1} \
|
||||
::gui::test::require {[llength $threats] == 1} \
|
||||
"ShotVis root does not contain exactly one threat combination"
|
||||
return [lindex $threats 0]
|
||||
}
|
||||
@@ -58,18 +58,18 @@ proc ::mged::xmin::shotvis::threat_combination {} {
|
||||
proc ::mged::xmin::shotvis::threat_cylinder {} {
|
||||
set threat [threat_combination]
|
||||
set cylinders [search $threat -type tgc -name \*.cyl]
|
||||
::xmin::test::require {[llength $cylinders] == 1} \
|
||||
::gui::test::require {[llength $cylinders] == 1} \
|
||||
"ShotVis threat does not contain exactly one cylinder"
|
||||
return [lindex $cylinders 0]
|
||||
}
|
||||
|
||||
proc ::mged::xmin::shotvis::set_validated_entry {entry value} {
|
||||
::xmin::test::require {[winfo exists $entry]} \
|
||||
::gui::test::require {[winfo exists $entry]} \
|
||||
"ShotVis entry '$entry' is unavailable"
|
||||
$entry delete 0 end
|
||||
$entry insert 0 $value
|
||||
::mged::xmin::test::settle
|
||||
::xmin::test::require {[$entry get] eq $value} \
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {[$entry get] eq $value} \
|
||||
"ShotVis entry '$entry' rejected '$value'"
|
||||
}
|
||||
|
||||
@@ -90,14 +90,14 @@ proc ::mged::xmin::shotvis::exercise_editor {} {
|
||||
variable basename
|
||||
|
||||
shotvis $basename
|
||||
::mged::xmin::test::require_mapped .shotvis ShotVis
|
||||
::xmin::test::require {
|
||||
::mged::gui::test::require_mapped .shotvis ShotVis
|
||||
::gui::test::require {
|
||||
[wm title .shotvis] eq "Edit Shotline Visualization - $basename" &&
|
||||
[exists $basename]
|
||||
} "ShotVis did not create its window and root combination"
|
||||
|
||||
set threat [threat_combination]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[attr get $threat shotvis_threat] == 1
|
||||
} "ShotVis threat combination lacks its identifying attribute"
|
||||
|
||||
@@ -120,15 +120,15 @@ proc ::mged::xmin::shotvis::exercise_editor {} {
|
||||
|
||||
set notebook $main.notebook
|
||||
$notebook select $notebook.nirt
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
$notebook select $notebook.threat
|
||||
::mged::xmin::test::settle
|
||||
::xmin::test::require {
|
||||
::mged::gui::test::settle
|
||||
::gui::test::require {
|
||||
[lsearch -exact [who] [threat_combination]] >= 0
|
||||
} "ShotVis did not redraw its threat after changing tabs"
|
||||
|
||||
::itcl::delete object .shotvis
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
![winfo exists .shotvis] && [exists $basename]
|
||||
} "ShotVis did not preserve its edited root when closed"
|
||||
}
|
||||
@@ -137,23 +137,23 @@ proc ::mged::xmin::shotvis::exercise_reload {} {
|
||||
variable basename
|
||||
|
||||
shotvis $basename
|
||||
::mged::xmin::test::require_mapped .shotvis {reloaded ShotVis}
|
||||
::mged::gui::test::require_mapped .shotvis {reloaded ShotVis}
|
||||
set cylinder [threat_cylinder]
|
||||
lassign [get $cylinder V] start_x start_y start_z
|
||||
require_near $start_x 25.0 "reloaded ShotVis start X"
|
||||
require_near [magnitude [get $cylinder H]] 250.0 \
|
||||
"reloaded ShotVis draw length"
|
||||
.shotvis update_shot
|
||||
::mged::xmin::test::settle
|
||||
::mged::gui::test::settle
|
||||
::itcl::delete object .shotvis
|
||||
::xmin::test::require {[exists $basename]} \
|
||||
::gui::test::require {[exists $basename]} \
|
||||
"reloaded ShotVis did not preserve its updated root"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::shotvis::run {id top} {
|
||||
variable basename
|
||||
set database [file join $::env(XMIN_TEST_DIR) shotvis.g]
|
||||
cd $::env(XMIN_TEST_DIR)
|
||||
set database [file join $::env(GUI_TEST_DIR) shotvis.g]
|
||||
cd $::env(GUI_TEST_DIR)
|
||||
file delete -force $database
|
||||
opendb $database y
|
||||
title {Xmin MGED ShotVis regression}
|
||||
@@ -163,7 +163,7 @@ proc ::mged::xmin::shotvis::run {id top} {
|
||||
exercise_math
|
||||
}
|
||||
|
||||
::mged::xmin::test::start ::mged::xmin::shotvis::run \
|
||||
::mged::gui::test::start ::mged::xmin::shotvis::run \
|
||||
{MGED ShotVis editing and persistence} {MGED ShotVis regression}
|
||||
|
||||
# Local Variables:
|
||||
|
||||
@@ -20,15 +20,15 @@
|
||||
###
|
||||
# Shared lifecycle and interaction helpers for focused MGED Xmin fixtures.
|
||||
|
||||
if {![info exists ::env(XMIN_GUI_LIBRARY)] ||
|
||||
![info exists ::env(XMIN_TEST_DIR)]} {
|
||||
puts stderr "XMIN_GUI_LIBRARY and XMIN_TEST_DIR are required"
|
||||
if {![info exists ::env(GUI_TEST_LIBRARY)] ||
|
||||
![info exists ::env(GUI_TEST_DIR)]} {
|
||||
puts stderr "GUI_TEST_LIBRARY and GUI_TEST_DIR are required"
|
||||
exit 2
|
||||
}
|
||||
source $::env(XMIN_GUI_LIBRARY)
|
||||
::xmin::test::capture_background_errors
|
||||
source $::env(GUI_TEST_LIBRARY)
|
||||
::gui::test::capture_background_errors
|
||||
|
||||
namespace eval ::mged::xmin::test {
|
||||
namespace eval ::mged::gui::test {
|
||||
variable dialog_error ""
|
||||
variable dialog_seen 0
|
||||
variable dialog_serial 0
|
||||
@@ -40,31 +40,31 @@ namespace eval ::mged::xmin::test {
|
||||
variable settle_serial 0
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::fail {message} {
|
||||
proc ::mged::gui::test::fail {message} {
|
||||
error $message
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::settle {} {
|
||||
proc ::mged::gui::test::settle {} {
|
||||
variable settle_delay_ms
|
||||
variable settle_serial
|
||||
set serial [incr settle_serial]
|
||||
after $settle_delay_ms [list set ::mged::xmin::test::settle_serial $serial]
|
||||
vwait ::mged::xmin::test::settle_serial
|
||||
after $settle_delay_ms [list set ::mged::gui::test::settle_serial $serial]
|
||||
vwait ::mged::gui::test::settle_serial
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::invoke {root labels} {
|
||||
::xmin::test::write progress "invoke: [join $labels { > }]"
|
||||
::xmin::test::invoke_menu_entry $root $labels
|
||||
proc ::mged::gui::test::invoke {root labels} {
|
||||
::gui::test::write progress "invoke: [join $labels { > }]"
|
||||
::gui::test::invoke_menu_entry $root $labels
|
||||
settle
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::set_entry {entry value} {
|
||||
proc ::mged::gui::test::set_entry {entry value} {
|
||||
$entry delete 0 end
|
||||
$entry insert 0 $value
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::find_descendant {root class} {
|
||||
foreach widget [::xmin::test::descendants $root] {
|
||||
proc ::mged::gui::test::find_descendant {root class} {
|
||||
foreach widget [::gui::test::descendants $root] {
|
||||
if {[winfo class $widget] eq $class} {
|
||||
return $widget
|
||||
}
|
||||
@@ -72,8 +72,8 @@ proc ::mged::xmin::test::find_descendant {root class} {
|
||||
fail "$root has no $class descendant"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::find_widget_by_text {root text} {
|
||||
foreach widget [::xmin::test::descendants $root] {
|
||||
proc ::mged::gui::test::find_widget_by_text {root text} {
|
||||
foreach widget [::gui::test::descendants $root] {
|
||||
if {![catch {$widget cget -text} label] && $label eq $text} {
|
||||
return $widget
|
||||
}
|
||||
@@ -81,7 +81,7 @@ proc ::mged::xmin::test::find_widget_by_text {root text} {
|
||||
fail "$root has no widget labeled '$text'"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::find_toplevel_by_title {title} {
|
||||
proc ::mged::gui::test::find_toplevel_by_title {title} {
|
||||
foreach widget [winfo children .] {
|
||||
if {![catch {wm title $widget} widget_title] &&
|
||||
$widget_title eq $title} {
|
||||
@@ -91,7 +91,7 @@ proc ::mged::xmin::test::find_toplevel_by_title {title} {
|
||||
fail "no toplevel has title '$title'"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::require_mapped {widget description} {
|
||||
proc ::mged::gui::test::require_mapped {widget description} {
|
||||
variable ready_retry_limit
|
||||
|
||||
for {set attempt 0} {$attempt < $ready_retry_limit} {incr attempt} {
|
||||
@@ -104,15 +104,15 @@ proc ::mged::xmin::test::require_mapped {widget description} {
|
||||
fail "$description is not mapped"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::return_file_dialog_path {path args} {
|
||||
proc ::mged::gui::test::return_file_dialog_path {path args} {
|
||||
return $path
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::with_file_dialog_path {command path script} {
|
||||
proc ::mged::gui::test::with_file_dialog_path {command path script} {
|
||||
set saved_command ${command}_xmin_saved
|
||||
rename $command $saved_command
|
||||
interp alias {} $command {} \
|
||||
::mged::xmin::test::return_file_dialog_path $path
|
||||
::mged::gui::test::return_file_dialog_path $path
|
||||
|
||||
set status [catch {uplevel 1 $script} result options]
|
||||
rename $command {}
|
||||
@@ -123,7 +123,7 @@ proc ::mged::xmin::test::with_file_dialog_path {command path script} {
|
||||
return $result
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::answer_dialog {
|
||||
proc ::mged::gui::test::answer_dialog {
|
||||
serial path expected_title entry value button
|
||||
} {
|
||||
variable dialog_error
|
||||
@@ -134,7 +134,7 @@ proc ::mged::xmin::test::answer_dialog {
|
||||
return
|
||||
}
|
||||
if {![winfo exists $path] || ![winfo ismapped $path]} {
|
||||
after 25 [list ::mged::xmin::test::answer_dialog $serial $path \
|
||||
after 25 [list ::mged::gui::test::answer_dialog $serial $path \
|
||||
$expected_title $entry $value $button]
|
||||
return
|
||||
}
|
||||
@@ -155,7 +155,7 @@ proc ::mged::xmin::test::answer_dialog {
|
||||
$button invoke
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::with_dialog_answer {
|
||||
proc ::mged::gui::test::with_dialog_answer {
|
||||
path expected_title entry value button script
|
||||
} {
|
||||
variable dialog_error
|
||||
@@ -165,7 +165,7 @@ proc ::mged::xmin::test::with_dialog_answer {
|
||||
set dialog_error ""
|
||||
set dialog_seen 0
|
||||
set serial [incr dialog_serial]
|
||||
after 25 [list ::mged::xmin::test::answer_dialog $serial $path \
|
||||
after 25 [list ::mged::gui::test::answer_dialog $serial $path \
|
||||
$expected_title $entry $value $button]
|
||||
set status [catch {uplevel 1 $script} result options]
|
||||
incr dialog_serial
|
||||
@@ -183,24 +183,24 @@ proc ::mged::xmin::test::with_dialog_answer {
|
||||
return $result
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::finish {status message} {
|
||||
proc ::mged::gui::test::finish {status message} {
|
||||
variable finished
|
||||
if {$finished} {
|
||||
return
|
||||
}
|
||||
set finished 1
|
||||
catch {update}
|
||||
lassign [::xmin::test::check_background_errors $status $message] \
|
||||
lassign [::gui::test::check_background_errors $status $message] \
|
||||
status message
|
||||
puts $message
|
||||
::xmin::test::write result $message
|
||||
::gui::test::write result $message
|
||||
if {$status != 0} {
|
||||
puts stderr $message
|
||||
}
|
||||
_mged_quit
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::run_checked {body pass_message failure_prefix} {
|
||||
proc ::mged::gui::test::run_checked {body pass_message failure_prefix} {
|
||||
global mged_gui mged_players
|
||||
variable ready_retries
|
||||
variable ready_retry_limit
|
||||
@@ -211,7 +211,7 @@ proc ::mged::xmin::test::run_checked {body pass_message failure_prefix} {
|
||||
finish 1 "FAIL: $failure_prefix: MGED did not create a GUI player"
|
||||
return
|
||||
}
|
||||
after $retry_delay_ms [list ::mged::xmin::test::run_checked \
|
||||
after $retry_delay_ms [list ::mged::gui::test::run_checked \
|
||||
$body $pass_message $failure_prefix]
|
||||
return
|
||||
}
|
||||
@@ -224,7 +224,7 @@ proc ::mged::xmin::test::run_checked {body pass_message failure_prefix} {
|
||||
finish 1 "FAIL: $failure_prefix: MGED did not finish mapping its GUI"
|
||||
return
|
||||
}
|
||||
after $retry_delay_ms [list ::mged::xmin::test::run_checked \
|
||||
after $retry_delay_ms [list ::mged::gui::test::run_checked \
|
||||
$body $pass_message $failure_prefix]
|
||||
return
|
||||
}
|
||||
@@ -234,7 +234,7 @@ proc ::mged::xmin::test::run_checked {body pass_message failure_prefix} {
|
||||
if {[dict exists $options -errorinfo]} {
|
||||
set error_info [dict get $options -errorinfo]
|
||||
puts stderr $error_info
|
||||
::xmin::test::write tcl_error_debug $error_info
|
||||
::gui::test::write tcl_error_debug $error_info
|
||||
}
|
||||
finish 1 "FAIL: $failure_prefix: $message"
|
||||
return
|
||||
@@ -242,8 +242,8 @@ proc ::mged::xmin::test::run_checked {body pass_message failure_prefix} {
|
||||
finish 0 "PASS: $pass_message"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::test::start {body pass_message failure_prefix} {
|
||||
after 25 [list ::mged::xmin::test::run_checked \
|
||||
proc ::mged::gui::test::start {body pass_message failure_prefix} {
|
||||
after 25 [list ::mged::gui::test::run_checked \
|
||||
$body $pass_message $failure_prefix]
|
||||
}
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
# Exercise MGED creation, browsing, and collaboration workflows through live
|
||||
# Tk controls and verify their database or display-state results.
|
||||
|
||||
if {![info exists ::env(XMIN_GUI_LIBRARY)] ||
|
||||
![info exists ::env(XMIN_TEST_DIR)]} {
|
||||
puts stderr "XMIN_GUI_LIBRARY and XMIN_TEST_DIR are required"
|
||||
if {![info exists ::env(GUI_TEST_LIBRARY)] ||
|
||||
![info exists ::env(GUI_TEST_DIR)]} {
|
||||
puts stderr "GUI_TEST_LIBRARY and GUI_TEST_DIR are required"
|
||||
exit 2
|
||||
}
|
||||
source $::env(XMIN_GUI_LIBRARY)
|
||||
::xmin::test::capture_background_errors
|
||||
source $::env(GUI_TEST_LIBRARY)
|
||||
::gui::test::capture_background_errors
|
||||
|
||||
namespace eval ::mged::xmin::workflows {
|
||||
variable dialog_seen 0
|
||||
@@ -69,8 +69,8 @@ proc ::mged::xmin::workflows::require_near {actual expected description} {
|
||||
}
|
||||
|
||||
proc ::mged::xmin::workflows::invoke {root labels} {
|
||||
::xmin::test::write progress "invoke: [join $labels { > }]"
|
||||
::xmin::test::invoke_menu_entry $root $labels
|
||||
::gui::test::write progress "invoke: [join $labels { > }]"
|
||||
::gui::test::invoke_menu_entry $root $labels
|
||||
settle
|
||||
}
|
||||
|
||||
@@ -193,10 +193,10 @@ proc ::mged::xmin::workflows::reject_edit {} {
|
||||
}
|
||||
|
||||
proc ::mged::xmin::workflows::assert_created {name panel context} {
|
||||
::xmin::test::require {[exists $name]} "$context did not create $name"
|
||||
::xmin::test::require {![winfo exists $panel]} \
|
||||
::gui::test::require {[exists $name]} "$context did not create $name"
|
||||
::gui::test::require {![winfo exists $panel]} \
|
||||
"$context did not dismiss its creation dialog"
|
||||
::xmin::test::require {[llength [get $name]] > 1} \
|
||||
::gui::test::require {[llength [get $name]] > 1} \
|
||||
"$context created an unreadable database object"
|
||||
reject_edit
|
||||
}
|
||||
@@ -207,9 +207,9 @@ proc ::mged::xmin::workflows::create_generic_primitive {id top type menu_path} {
|
||||
set name xmin_$type.s
|
||||
invoke $top [concat $menu_path [list [format "%s..." $type]]]
|
||||
set panel .$id.make_solid
|
||||
::xmin::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
::gui::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
"Create $type did not open the generic primitive dialog"
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[string first $type [$panel.nameL cget -text]] >= 0
|
||||
} "Create $type opened a dialog for the wrong primitive type"
|
||||
|
||||
@@ -272,42 +272,42 @@ proc ::mged::xmin::workflows::write_text_file {path contents} {
|
||||
proc ::mged::xmin::workflows::exercise_file_operations {id top database} {
|
||||
global ex_control
|
||||
|
||||
set extracted_database [file join $::env(XMIN_TEST_DIR) extracted.g]
|
||||
set extracted_database [file join $::env(GUI_TEST_DIR) extracted.g]
|
||||
invoke $top {File Export {Database Objects}}
|
||||
set extract_panel .$id.do_extract
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[winfo exists $extract_panel] && [winfo ismapped $extract_panel]
|
||||
} "Database Objects export did not open the Extract Objects dialog"
|
||||
set ex_control($id,file) $extracted_database
|
||||
set ex_control($id,objects) xmin_arb8.s
|
||||
$extract_panel.okB invoke
|
||||
settle
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[file exists $extracted_database] && [file size $extracted_database] > 0
|
||||
} "Database Objects export did not write a database"
|
||||
|
||||
set ascii_database [file join $::env(XMIN_TEST_DIR) workflows.asc]
|
||||
set ascii_database [file join $::env(GUI_TEST_DIR) workflows.asc]
|
||||
with_file_dialog_path ::tk_getSaveFile $ascii_database \
|
||||
[list invoke $top {File Export {Ascii Database}}]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[file exists $ascii_database] && [file size $ascii_database] > 0
|
||||
} "Ascii Database export did not write a file"
|
||||
|
||||
set script [file join $::env(XMIN_TEST_DIR) loaded-script.tcl]
|
||||
set script [file join $::env(GUI_TEST_DIR) loaded-script.tcl]
|
||||
write_text_file $script \
|
||||
{set ::mged::xmin::workflows::script_loaded 1}
|
||||
set ::mged::xmin::workflows::script_loaded 0
|
||||
with_file_dialog_path ::tk_getOpenFile $script \
|
||||
[list with_dialog_answer .mged_dialog {Script loaded} "" "" \
|
||||
[list invoke $top {File {Load Script...}}]]
|
||||
::xmin::test::require {$::mged::xmin::workflows::script_loaded} \
|
||||
::gui::test::require {$::mged::xmin::workflows::script_loaded} \
|
||||
"Load Script did not evaluate the selected Tcl file"
|
||||
|
||||
set new_database [file join $::env(XMIN_TEST_DIR) new-database.g]
|
||||
set new_database [file join $::env(GUI_TEST_DIR) new-database.g]
|
||||
with_file_dialog_path ::tk_getSaveFile $new_database \
|
||||
[list with_dialog_answer .mged_dialog {File created} "" "" \
|
||||
[list invoke $top {File {New...}}]]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[file exists $new_database] &&
|
||||
[file normalize [_mged_opendb]] eq [file normalize $new_database]
|
||||
} "New did not create and open the selected database"
|
||||
@@ -315,7 +315,7 @@ proc ::mged::xmin::workflows::exercise_file_operations {id top database} {
|
||||
with_file_dialog_path ::tk_getOpenFile $database \
|
||||
[list with_dialog_answer .mged_dialog {File loaded} "" "" \
|
||||
[list invoke $top {File {Open...}}]]
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[file normalize [_mged_opendb]] eq [file normalize $database] &&
|
||||
[exists xmin_arb8.s]
|
||||
} "Open did not restore the selected database"
|
||||
@@ -323,25 +323,25 @@ proc ::mged::xmin::workflows::exercise_file_operations {id top database} {
|
||||
with_file_dialog_path ::tk_getOpenFile $extracted_database \
|
||||
[list with_dialog_answer .$id.prefix Prefix .$id.prefix.mid.ent bin_ \
|
||||
[list invoke $top {File Import {Binary Database}}]]
|
||||
::xmin::test::require {[exists bin_xmin_arb8.s]} \
|
||||
::gui::test::require {[exists bin_xmin_arb8.s]} \
|
||||
"Binary Database import did not apply its prefix"
|
||||
|
||||
with_file_dialog_path ::tk_getOpenFile $ascii_database \
|
||||
[list with_dialog_answer .$id.prefix Prefix .$id.prefix.mid.ent asc_ \
|
||||
[list invoke $top {File Import {Ascii Database}}]]
|
||||
::xmin::test::require {[exists asc_xmin_arb8.s]} \
|
||||
::gui::test::require {[exists asc_xmin_arb8.s]} \
|
||||
"Ascii Database import did not apply its prefix"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::workflows::exercise_dsp_creation {id top} {
|
||||
global mged_gui
|
||||
|
||||
set data_file [file join $::env(XMIN_TEST_DIR) dsp-data.bw]
|
||||
set data_file [file join $::env(GUI_TEST_DIR) dsp-data.bw]
|
||||
write_binary_file $data_file [binary format S* {0 1 2 3}]
|
||||
|
||||
invoke $top {Create dsp...}
|
||||
set panel .$id.make_dsp
|
||||
::xmin::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
::gui::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
"Create dsp did not open its specialized dialog"
|
||||
|
||||
set name xmin_dsp.s
|
||||
@@ -357,12 +357,12 @@ proc ::mged::xmin::workflows::exercise_dsp_creation {id top} {
|
||||
}
|
||||
|
||||
proc ::mged::xmin::workflows::exercise_binunif_creation {id top} {
|
||||
set data_file [file join $::env(XMIN_TEST_DIR) binunif-data.bin]
|
||||
set data_file [file join $::env(GUI_TEST_DIR) binunif-data.bin]
|
||||
write_binary_file $data_file [binary format c* {1 2 3 4}]
|
||||
|
||||
invoke $top {Create binunif...}
|
||||
set panel .$id.make_binunif
|
||||
::xmin::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
::gui::test::require {[winfo exists $panel] && [winfo ismapped $panel]} \
|
||||
"Create binunif did not open its specialized dialog"
|
||||
|
||||
set name xmin_binunif
|
||||
@@ -378,11 +378,11 @@ proc ::mged::xmin::workflows::exercise_binunif_creation {id top} {
|
||||
proc ::mged::xmin::workflows::exercise_geometry_browser {id top} {
|
||||
invoke $top {Tools {Geometry Browser}}
|
||||
set browser .$id.geometree
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[llength [info commands $browser]] == 1 &&
|
||||
[winfo exists $browser] && [winfo ismapped $browser]
|
||||
} "Geometry Browser did not open"
|
||||
::xmin::test::require {[wm title $browser] eq "Geometry Browser"} \
|
||||
::gui::test::require {[wm title $browser] eq "Geometry Browser"} \
|
||||
"Geometry Browser has an unexpected title"
|
||||
|
||||
set children [$browser getNodeChildren "" yes]
|
||||
@@ -390,55 +390,55 @@ proc ::mged::xmin::workflows::exercise_geometry_browser {id top} {
|
||||
foreach child $children {
|
||||
lappend roots [lindex $child 0]
|
||||
}
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lsearch -exact $roots /xmin_arb8.s] >= 0 &&
|
||||
[lsearch -exact $roots /xmin_binunif] >= 0
|
||||
} "Geometry Browser did not populate the isolated database"
|
||||
|
||||
::xmin::test::write progress "browser: display"
|
||||
::gui::test::write progress "browser: display"
|
||||
$browser displayNode /xmin_arb8.s alone
|
||||
settle
|
||||
::xmin::test::require {[lsearch -exact [who] xmin_arb8.s] >= 0} \
|
||||
::gui::test::require {[lsearch -exact [who] xmin_arb8.s] >= 0} \
|
||||
"Geometry Browser did not display the selected primitive"
|
||||
::xmin::test::write progress "browser: autosize"
|
||||
::gui::test::write progress "browser: autosize"
|
||||
$browser autosizeDisplay
|
||||
::xmin::test::write progress "browser: zoom"
|
||||
::gui::test::write progress "browser: zoom"
|
||||
$browser zoomDisplay in
|
||||
$browser zoomDisplay out
|
||||
::xmin::test::write progress "browser: clear"
|
||||
::gui::test::write progress "browser: clear"
|
||||
$browser clearDisplay
|
||||
settle
|
||||
::xmin::test::require {[who] eq ""} \
|
||||
::gui::test::require {[who] eq ""} \
|
||||
"Geometry Browser did not clear the display"
|
||||
|
||||
::xmin::test::write progress "browser: close"
|
||||
::gui::test::write progress "browser: close"
|
||||
set file_menu [$browser.menubar entrycget 0 -menu]
|
||||
::xmin::test::require {[$file_menu entrycget 0 -label] eq "Close"} \
|
||||
::gui::test::require {[$file_menu entrycget 0 -label] eq "Close"} \
|
||||
"Geometry Browser does not expose its Close command"
|
||||
|
||||
$file_menu invoke 0
|
||||
settle
|
||||
::xmin::test::require {![winfo exists $browser]} "Geometry Browser did not close"
|
||||
::gui::test::require {![winfo exists $browser]} "Geometry Browser did not close"
|
||||
}
|
||||
|
||||
proc ::mged::xmin::workflows::exercise_collaboration {id} {
|
||||
global mged_collaborators mged_gui mged_players
|
||||
|
||||
::xmin::test::write progress "collaboration: join primary"
|
||||
::gui::test::write progress "collaboration: join primary"
|
||||
if {[lsearch -exact $mged_collaborators $id] < 0} {
|
||||
collaborate join $id
|
||||
}
|
||||
|
||||
set peer xmin_peer
|
||||
::xmin::test::write progress "collaboration: create peer"
|
||||
::gui::test::write progress "collaboration: create peer"
|
||||
set result [gui -config b -dt tkswrast -id $peer -join]
|
||||
if {$result ne ""} {
|
||||
fail "could not create collaborating MGED player: $result"
|
||||
}
|
||||
settle
|
||||
::xmin::test::write progress "collaboration: peer created"
|
||||
::gui::test::write progress "collaboration: peer created"
|
||||
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lsearch -exact $mged_players $peer] >= 0 &&
|
||||
[lsearch -exact $mged_collaborators $peer] >= 0 &&
|
||||
$mged_gui($peer,collaborate)
|
||||
@@ -453,7 +453,7 @@ proc ::mged::xmin::workflows::exercise_collaboration {id} {
|
||||
require_near [size] {123} "collaborative view size"
|
||||
|
||||
collaborate quit $peer
|
||||
::xmin::test::require {
|
||||
::gui::test::require {
|
||||
[lsearch -exact $mged_collaborators $peer] < 0 &&
|
||||
!$mged_gui($peer,collaborate)
|
||||
} "second MGED player did not leave the collaborative session"
|
||||
@@ -461,7 +461,7 @@ proc ::mged::xmin::workflows::exercise_collaboration {id} {
|
||||
set mged_gui($peer,show_cmd) 0
|
||||
set mged_gui($peer,show_dm) 0
|
||||
gui_destroy $peer
|
||||
::xmin::test::require {[lsearch -exact $mged_players $peer] < 0} \
|
||||
::gui::test::require {[lsearch -exact $mged_players $peer] < 0} \
|
||||
"second MGED player did not shut down cleanly"
|
||||
|
||||
collaborate quit $id
|
||||
@@ -475,10 +475,10 @@ proc ::mged::xmin::workflows::finish {status message} {
|
||||
}
|
||||
set finished 1
|
||||
catch {update}
|
||||
lassign [::xmin::test::check_background_errors $status $message] \
|
||||
lassign [::gui::test::check_background_errors $status $message] \
|
||||
status message
|
||||
puts $message
|
||||
::xmin::test::write result $message
|
||||
::gui::test::write result $message
|
||||
if {$status != 0} {
|
||||
puts stderr $message
|
||||
}
|
||||
@@ -509,8 +509,8 @@ proc ::mged::xmin::workflows::run {} {
|
||||
return
|
||||
}
|
||||
|
||||
set database [file join $::env(XMIN_TEST_DIR) workflows.g]
|
||||
cd $::env(XMIN_TEST_DIR)
|
||||
set database [file join $::env(GUI_TEST_DIR) workflows.g]
|
||||
cd $::env(GUI_TEST_DIR)
|
||||
file delete -force $database
|
||||
opendb $database y
|
||||
title {Xmin MGED workflow regression}
|
||||
@@ -530,7 +530,7 @@ proc ::mged::xmin::workflows::run_checked {} {
|
||||
if {[dict exists $options -errorinfo]} {
|
||||
set error_info [dict get $options -errorinfo]
|
||||
puts stderr $error_info
|
||||
::xmin::test::write tcl_error_debug $error_info
|
||||
::gui::test::write tcl_error_debug $error_info
|
||||
}
|
||||
finish 1 "FAIL: MGED workflow regression: $message"
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
set -eu
|
||||
|
||||
: "${XMIN_TEST_SHELL:?XMIN_TEST_SHELL is required}"
|
||||
. "$XMIN_TEST_SHELL"
|
||||
: "${GUI_TEST_SHELL:?GUI_TEST_SHELL is required}"
|
||||
. "$GUI_TEST_SHELL"
|
||||
|
||||
window=$1
|
||||
geometry=$("$XMIN_CTL" geometry "$window") ||
|
||||
xmin_fail "could not query qged window geometry"
|
||||
geometry=$("$GUI_TEST_CTL" geometry "$window") ||
|
||||
gui_fail "could not query qged window geometry"
|
||||
set -- $geometry
|
||||
width=$3
|
||||
height=$4
|
||||
@@ -17,9 +17,9 @@ height=$4
|
||||
# that changes the OpenGL view without depending on evolving qged controls.
|
||||
console_x=$((width / 2))
|
||||
console_y=$((height * 94 / 100))
|
||||
"$XMIN_CTL" click "$window" "$console_x" "$console_y" 1
|
||||
"$XMIN_CTL" type "draw all.g"
|
||||
"$XMIN_CTL" key enter
|
||||
"$GUI_TEST_CTL" click "$window" "$console_x" "$console_y" 1
|
||||
"$GUI_TEST_CTL" type "draw all.g"
|
||||
"$GUI_TEST_CTL" key enter
|
||||
QGED_DRAW_SETTLE_SECONDS=${QGED_DRAW_SETTLE_SECONDS:-2}
|
||||
sleep "$QGED_DRAW_SETTLE_SECONDS"
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
set -eu
|
||||
|
||||
: "${XMIN_ARTIFACT_DIR:?XMIN_ARTIFACT_DIR is required}"
|
||||
: "${GUI_ARTIFACT_DIR:?GUI_ARTIFACT_DIR is required}"
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: $0 qged [argument ...]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
XDG_CONFIG_HOME="$XMIN_ARTIFACT_DIR/config"
|
||||
XDG_CONFIG_HOME="$GUI_ARTIFACT_DIR/config"
|
||||
export XDG_CONFIG_HOME
|
||||
|
||||
exec "$@"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user