Compare commits
45
Commits
brepraytrace
...
STABLE
| 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 |
@@ -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() }}
|
||||
|
||||
+5
-4
@@ -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(0682795bcfe34644c17e5a4bdd0225c76f6bdc98)
|
||||
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.
|
||||
|
||||
@@ -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,80 +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 ---
|
||||
----------------------------------------------------------------------
|
||||
|
||||
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
|
||||
* updated MGED and Archer for Tcl 8.6.18 and Itcl/Itk 4 - Cliff Yapp
|
||||
* 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 under Itcl 4 - Cliff Yapp
|
||||
* fixed Archer shutdown menu cleanup errors - Cliff Yapp
|
||||
* fixed MGED Build Pattern dialog under Itcl 4 - 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
|
||||
@@ -105,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
|
||||
@@ -133,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
|
||||
@@ -144,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
|
||||
@@ -163,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
|
||||
@@ -272,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
|
||||
@@ -544,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
|
||||
@@ -582,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
|
||||
|
||||
@@ -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
-1
@@ -1 +1 @@
|
||||
45
|
||||
46
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1108,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()
|
||||
@@ -1121,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()
|
||||
|
||||
@@ -1840,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)
|
||||
|
||||
@@ -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
|
||||
@@ -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.\
|
||||
\
|
||||
|
||||
+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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -68,6 +68,7 @@ set(
|
||||
sca_view.mged
|
||||
search_exec.mged
|
||||
sed.mged
|
||||
sed_reset.mged
|
||||
set_perspective.mged
|
||||
setview.mged
|
||||
size.mged
|
||||
@@ -145,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")
|
||||
|
||||
@@ -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 ***"
|
||||
|
||||
@@ -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"
|
||||
@@ -144,6 +144,18 @@ if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND
|
||||
)
|
||||
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()
|
||||
|
||||
@@ -201,6 +213,7 @@ cmakefiles(
|
||||
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
|
||||
|
||||
@@ -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
|
||||
@@ -50,6 +50,18 @@ proc ::mged::xmin::help::exercise_command_manual {top} {
|
||||
::gui::test::require {
|
||||
[llength $selection] == 1 && [$toc get $selection] eq "rt"
|
||||
} "man rt did not select and load the rt manual page"
|
||||
|
||||
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
|
||||
@@ -151,10 +163,38 @@ proc ::mged::xmin::help::exercise_html_manual {top} {
|
||||
set mged_browser [file join $::env(GUI_TEST_DIR) missing-browser]
|
||||
::mged::gui::test::invoke $top {Help Manual}
|
||||
set fallback $top.man
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -72,17 +72,15 @@ set(archer_wizard_FILES
|
||||
)
|
||||
|
||||
if(BRLCAD_ENABLE_TCL)
|
||||
brlcad_adddata(archer_utility_FILES plugins/archer/Utility)
|
||||
brlcad_adddata(archer_wizard_FILES plugins/archer/Wizards)
|
||||
# Archer scans only the plugin category directories for registration scripts.
|
||||
# Keep class definitions in their subdirectories so they are not sourced twice.
|
||||
foreach(plugin_file IN LISTS archer_utility_FILES archer_wizard_FILES)
|
||||
get_filename_component(plugin_dir "${plugin_file}" DIRECTORY)
|
||||
file(RELATIVE_PATH plugin_dir "${CMAKE_CURRENT_SOURCE_DIR}/plugins" "${CMAKE_CURRENT_SOURCE_DIR}/${plugin_dir}")
|
||||
brlcad_adddata("${plugin_file}" "plugins/archer/${plugin_dir}")
|
||||
endforeach()
|
||||
brlcad_adddata(plugins/Commands/README plugins/archer/Command)
|
||||
brlcad_adddata(plugins/Core/README plugins/archer/Core)
|
||||
brlcad_adddata(plugins/Utility/attrGroupsDisplayUtilityP/AttrGroupsDisplayUtilityP.tcl plugins/archer/Utility/attrGroupsDisplayUtilityP)
|
||||
brlcad_adddata(plugins/Utility/botUtilityP/BotUtilityP.tcl plugins/archer/Utility/botUtilityP)
|
||||
brlcad_adddata(plugins/Utility/lodUtilityP/LODUtilityP.tcl plugins/archer/Utility/lodUtilityP)
|
||||
brlcad_adddata(plugins/Wizards/humanwizard/HumanWizard.tcl plugins/archer/Wizards/humanwizard)
|
||||
brlcad_adddata(plugins/Wizards/tankwizard/TankWizard.tcl plugins/archer/Wizards/tankwizard)
|
||||
brlcad_adddata(plugins/Wizards/tankwizard/images/tank.png plugins/archer/Wizards/tankwizardIA/images)
|
||||
brlcad_adddata(plugins/Wizards/tirewizard/TireWizard.tcl plugins/archer/Wizards/tirewizard)
|
||||
endif(BRLCAD_ENABLE_TCL)
|
||||
|
||||
set(
|
||||
|
||||
@@ -23,10 +23,20 @@
|
||||
#include "InformationGatherer.h"
|
||||
#include "bu/log.h"
|
||||
|
||||
// flush results, if we have any, then exit
|
||||
static void reportAndExit(const std::string &message, const std::string &result = "")
|
||||
{
|
||||
if (!result.empty())
|
||||
bu_log("%s%s", result.c_str(), result.back() == '\n' ? "" : "\n");
|
||||
|
||||
bu_exit(BRLCAD_ERROR, "%s", message.c_str());
|
||||
}
|
||||
|
||||
|
||||
std::string getCmdPath(std::string exeDir, const char* cmd) {
|
||||
char buf[MAXPATHLEN] = {0};
|
||||
if (!bu_dir(buf, MAXPATHLEN, exeDir.c_str(), cmd, BU_DIR_EXT, NULL))
|
||||
bu_exit(BRLCAD_ERROR, "Couldn't find %s, aborting.\n", cmd);
|
||||
reportAndExit("Couldn't find " + std::string(cmd) + ", aborting.\n");
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
@@ -58,13 +68,13 @@ getSurfaceArea(Options* opt, std::map<std::string, std::string> UNUSED(map), std
|
||||
bu_process_create(&p, rtarea_av, BU_PROCESS_HIDE_WINDOW | BU_PROCESS_OUT_EQ_ERR);
|
||||
|
||||
if (bu_process_pid(p) <= 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem with getSurfaceArea, aborting\n");
|
||||
reportAndExit("Problem with getSurfaceArea, aborting\n");
|
||||
}
|
||||
|
||||
char buffer[128];
|
||||
std::string result = "";
|
||||
std::string result;
|
||||
int read_cnt = 0;
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, 128-1, buffer)) > 0) {
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, sizeof(buffer) - 1, buffer)) > 0) {
|
||||
/* NOTE: read does not ensure null-termination, thus buffersize-1 */
|
||||
buffer[read_cnt] = '\0';
|
||||
result += buffer;
|
||||
@@ -80,7 +90,7 @@ getSurfaceArea(Options* opt, std::map<std::string, std::string> UNUSED(map), std
|
||||
try {
|
||||
surfArea += stod(result);
|
||||
} catch (const std::invalid_argument& ia) {
|
||||
bu_exit(BRLCAD_ERROR, "Invalid argument for getSurfaceArea. Got (%s), aborting.\n", ia.what());
|
||||
reportAndExit("Invalid argument for getSurfaceArea. Got (" + std::string(ia.what()) + "), aborting.\n", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,7 +210,7 @@ getVerificationData(struct ged* UNUSED(g), Options* opt, std::map<std::string, s
|
||||
struct bu_process* p;
|
||||
int read_cnt = 0;
|
||||
char buffer[1024] = {0};
|
||||
std::string result = "";
|
||||
std::string result;
|
||||
std::string ncpu(std::to_string(opt->getNCPU()));
|
||||
std::string dFile(opt->getDensityFile());
|
||||
|
||||
@@ -233,21 +243,23 @@ getVerificationData(struct ged* UNUSED(g), Options* opt, std::map<std::string, s
|
||||
bu_process_create(&p, const_cast<const char**>(gqa_av_vec.data()), BU_PROCESS_HIDE_WINDOW | BU_PROCESS_OUT_EQ_ERR);
|
||||
|
||||
if (bu_process_pid(p) <= 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem in getVerificationData gqa process creation, aborting\n");
|
||||
reportAndExit("Problem in getVerificationData gqa process creation, aborting\n");
|
||||
}
|
||||
|
||||
result = "";
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, 1024-1, buffer)) > 0) {
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, sizeof(buffer) - 1, buffer)) > 0) {
|
||||
buffer[read_cnt] = '\0';
|
||||
result += buffer;
|
||||
}
|
||||
|
||||
if (bu_process_wait_n(&p, 0) != 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem collecting gqa volume and mass, aborting\n");
|
||||
const int gqa_status = bu_process_wait_n(&p, 0);
|
||||
|
||||
// sanity - we should have clean status code and not the "no density found" message
|
||||
const bool no_density_data = result.find(no_density_msg) != std::string::npos;
|
||||
if (gqa_status != 0 && (!no_density_data || !dFile.empty())) {
|
||||
reportAndExit("Problem collecting gqa volume and mass, aborting\n", result);
|
||||
}
|
||||
|
||||
// make sure we did not get 'no density file' error message
|
||||
if (result.find(no_density_msg) == std::string::npos) {
|
||||
if (!no_density_data) {
|
||||
// NOTE: tmp_val is zeroed at each parseLabeledNumber call
|
||||
if (parseLabeledNumber(tmp_val, result, volume_label))
|
||||
volume += tmp_val;
|
||||
@@ -263,17 +275,17 @@ getVerificationData(struct ged* UNUSED(g), Options* opt, std::map<std::string, s
|
||||
bu_process_create(&p, const_cast<const char**>(gqa_av_vec.data()), BU_PROCESS_HIDE_WINDOW | BU_PROCESS_OUT_EQ_ERR);
|
||||
|
||||
if (bu_process_pid(p) <= 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem in getVerificationData gqa process creation, aborting\n");
|
||||
reportAndExit("Problem in getVerificationData gqa process creation, aborting\n");
|
||||
}
|
||||
|
||||
result = "";
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, 1024-1, buffer)) > 0) {
|
||||
result.clear();
|
||||
while ((read_cnt = bu_process_read_n(p, BU_PROCESS_STDOUT, sizeof(buffer) - 1, buffer)) > 0) {
|
||||
buffer[read_cnt] = '\0';
|
||||
result += buffer;
|
||||
}
|
||||
|
||||
if (bu_process_wait_n(&p, 0) != 0) {
|
||||
bu_exit(BRLCAD_ERROR, "Problem collecting gqa volume, aborting\n");
|
||||
reportAndExit("Problem collecting gqa volume, aborting\n", result);
|
||||
}
|
||||
|
||||
if (parseLabeledNumber(tmp_val, result, volume_label))
|
||||
@@ -381,7 +393,7 @@ InformationGatherer::getMainComp()
|
||||
ged_exec_exists(g, 2, cmd);
|
||||
std::string res = bu_vls_addr(g->ged_result_str);
|
||||
if (res != "1") {
|
||||
bu_exit(BRLCAD_ERROR, "Could not find component (%s), aborting.\n", topname);
|
||||
reportAndExit("Could not find component (" + topcomp + "), aborting.\n");
|
||||
}
|
||||
|
||||
int entities = getNumEntities(opt->getTopComp());
|
||||
|
||||
+3
-2
@@ -43,6 +43,7 @@ main(int argc, char *argv[])
|
||||
int i, j;
|
||||
int db_index;
|
||||
int c;
|
||||
int ret;
|
||||
const char **av;
|
||||
struct ged *gedp;
|
||||
|
||||
@@ -103,14 +104,14 @@ main(int argc, char *argv[])
|
||||
bu_exit(1, usage, argv[0]);
|
||||
}
|
||||
|
||||
(void)ged_exec_gqa(gedp, j, av);
|
||||
ret = ged_exec_gqa(gedp, j, av);
|
||||
if (bu_vls_strlen(gedp->ged_result_str) > 0)
|
||||
bu_log("%s", bu_vls_addr(gedp->ged_result_str));
|
||||
ged_close(gedp);
|
||||
|
||||
bu_free((void *)av, "av");
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@ extern int gettimeofday(struct timeval *, void *);
|
||||
|
||||
static constexpr int64_t usec_per_sec = 1000000;
|
||||
static constexpr int64_t nsec_per_sec = 1000000000;
|
||||
static constexpr int64_t nsec_per_usec = 1000;
|
||||
#if defined(HAVE_GETPROCESSTIMES) || defined(HAVE_GETTHREADTIMES)
|
||||
static constexpr int64_t nsec_per_windows_tick = 100;
|
||||
#endif
|
||||
@@ -107,7 +106,7 @@ timer_rusage(const struct rusage *usage)
|
||||
+ (int64_t)usage->ru_stime.tv_sec * usec_per_sec
|
||||
+ (int64_t)usage->ru_stime.tv_usec;
|
||||
|
||||
return usec * nsec_per_usec;
|
||||
return usec * (nsec_per_sec / usec_per_sec);
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +148,7 @@ static int64_t
|
||||
timer_mach_time_val(const time_value_t *time_val)
|
||||
{
|
||||
return ((int64_t)time_val->seconds * nsec_per_sec
|
||||
+ (int64_t)time_val->microseconds * nsec_per_usec);
|
||||
+ (int64_t)time_val->microseconds * (nsec_per_sec / usec_per_sec));
|
||||
}
|
||||
|
||||
static int64_t
|
||||
|
||||
+10
-2
@@ -891,8 +891,8 @@ Done:
|
||||
int
|
||||
ogl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
{
|
||||
struct gl_vars *mvars = (struct gl_vars *)dmp1->i->m_vars;
|
||||
struct pogl_vars *privars = (struct pogl_vars *)dmp1->i->dm_vars.priv_vars;
|
||||
struct gl_vars *mvars;
|
||||
struct pogl_vars *privars;
|
||||
GLfloat backgnd[4];
|
||||
GLfloat vf;
|
||||
GLXContext old_glxContext;
|
||||
@@ -900,6 +900,9 @@ ogl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
if (dmp1 == (struct dm *)NULL)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
mvars = (struct gl_vars *)dmp1->i->m_vars;
|
||||
privars = (struct pogl_vars *)dmp1->i->dm_vars.priv_vars;
|
||||
|
||||
if (dmp2 == (struct dm *)NULL) {
|
||||
/* create a new graphics context for dmp1 with private display lists */
|
||||
|
||||
@@ -1053,6 +1056,11 @@ ogl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
glXDestroyContext(((struct dm_glxvars *)dmp2->i->dm_vars.pub_vars)->dpy, old_glxContext);
|
||||
}
|
||||
|
||||
struct dm *target_dmp = dmp2 ? dmp2 : dmp1;
|
||||
struct gl_vars *target_mvars = (struct gl_vars *)target_dmp->i->m_vars;
|
||||
gl_setZBuffer(target_dmp, target_mvars->zbuffer_on);
|
||||
gl_setLight(target_dmp, target_mvars->lighting_on);
|
||||
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,11 +88,13 @@ wgl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
GLfloat backgnd[4];
|
||||
GLfloat vf;
|
||||
HGLRC old_glxContext;
|
||||
struct gl_vars *mvars = (struct gl_vars *)dmp1->i->m_vars;
|
||||
struct gl_vars *mvars;
|
||||
|
||||
if (dmp1 == (struct dm *)NULL)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
mvars = (struct gl_vars *)dmp1->i->m_vars;
|
||||
|
||||
if (dmp2 == (struct dm *)NULL) {
|
||||
/* create a new graphics context for dmp1 with private display lists */
|
||||
|
||||
@@ -244,6 +246,11 @@ wgl_share_dlist(struct dm *dmp1, struct dm *dmp2)
|
||||
wglDeleteContext(old_glxContext);
|
||||
}
|
||||
|
||||
struct dm *target_dmp = dmp2 ? dmp2 : dmp1;
|
||||
struct gl_vars *target_mvars = (struct gl_vars *)target_dmp->i->m_vars;
|
||||
gl_setZBuffer(target_dmp, target_mvars->zbuffer_on);
|
||||
gl_setLight(target_dmp, target_mvars->lighting_on);
|
||||
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
+115
-33
@@ -138,30 +138,37 @@ static const char *p_nmgin[] = {
|
||||
|
||||
|
||||
#define ARB_FACE_COUNT 6
|
||||
#define ARB_MAX_PLANE_INTERSECTIONS 20
|
||||
|
||||
|
||||
/* Verify that every plane bounds a non-degenerate convex volume. Translating
|
||||
* the planes of an existing convex ARB cannot make their intersection
|
||||
* the planes of an existing convex polyhedron cannot make their intersection
|
||||
* unbounded, but excessive or unequal thicknesses can eliminate a face or
|
||||
* collapse the volume. */
|
||||
static int
|
||||
arb_in_planes_valid(plane_t planes[ARB_FACE_COUNT], const struct bn_tol *tol)
|
||||
in_planes_valid(const plane_t *planes, size_t plane_count,
|
||||
const struct bn_tol *tol)
|
||||
{
|
||||
point_t vertices[ARB_MAX_PLANE_INTERSECTIONS];
|
||||
int plane_used[ARB_FACE_COUNT] = {0};
|
||||
size_t vertex_count = 0;
|
||||
point_t basis[3];
|
||||
plane_t basis_plane;
|
||||
size_t basis_count = 0;
|
||||
int have_volume = 0;
|
||||
|
||||
for (size_t i = 0; i < ARB_FACE_COUNT - 2; i++) {
|
||||
for (size_t j = i + 1; j < ARB_FACE_COUNT - 1; j++) {
|
||||
for (size_t k = j + 1; k < ARB_FACE_COUNT; k++) {
|
||||
if (!planes || plane_count < 4)
|
||||
return 0;
|
||||
|
||||
int *plane_used = (int *)bu_calloc(plane_count, sizeof(int),
|
||||
"inside plane use flags");
|
||||
|
||||
for (size_t i = 0; i < plane_count - 2; i++) {
|
||||
for (size_t j = i + 1; j < plane_count - 1; j++) {
|
||||
for (size_t k = j + 1; k < plane_count; k++) {
|
||||
point_t candidate;
|
||||
int outside = 0;
|
||||
|
||||
if (bg_make_pnt_3planes(candidate, planes[i], planes[j], planes[k]) < 0)
|
||||
continue;
|
||||
|
||||
for (size_t face = 0; face < ARB_FACE_COUNT; face++) {
|
||||
for (size_t face = 0; face < plane_count; face++) {
|
||||
if (DIST_PNT_PLANE(candidate, planes[face]) > tol->dist) {
|
||||
outside = 1;
|
||||
break;
|
||||
@@ -173,35 +180,39 @@ arb_in_planes_valid(plane_t planes[ARB_FACE_COUNT], const struct bn_tol *tol)
|
||||
plane_used[i] = 1;
|
||||
plane_used[j] = 1;
|
||||
plane_used[k] = 1;
|
||||
VMOVE(vertices[vertex_count], candidate);
|
||||
vertex_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t face = 0; face < ARB_FACE_COUNT; face++)
|
||||
if (!plane_used[face])
|
||||
return 0;
|
||||
|
||||
/* At least four non-coplanar vertices are required for a volume. */
|
||||
for (size_t i = 0; i + 2 < vertex_count; i++) {
|
||||
for (size_t j = i + 1; j + 1 < vertex_count; j++) {
|
||||
for (size_t k = j + 1; k < vertex_count; k++) {
|
||||
plane_t vertex_plane;
|
||||
|
||||
if (bg_make_plane_3pnts(vertex_plane, vertices[i], vertices[j], vertices[k], tol) < 0)
|
||||
if (have_volume)
|
||||
continue;
|
||||
for (size_t l = 0; l < vertex_count; l++) {
|
||||
if (l == i || l == j || l == k)
|
||||
continue;
|
||||
if (!NEAR_ZERO(DIST_PNT_PLANE(vertices[l], vertex_plane), tol->dist))
|
||||
return 1;
|
||||
if (!basis_count) {
|
||||
VMOVE(basis[0], candidate);
|
||||
basis_count = 1;
|
||||
} else if (basis_count == 1 &&
|
||||
DIST_PNT_PNT_SQ(basis[0], candidate) > tol->dist_sq) {
|
||||
VMOVE(basis[1], candidate);
|
||||
basis_count = 2;
|
||||
} else if (basis_count == 2 &&
|
||||
bg_make_plane_3pnts(basis_plane, basis[0], basis[1],
|
||||
candidate, tol) == 0) {
|
||||
VMOVE(basis[2], candidate);
|
||||
basis_count = 3;
|
||||
} else if (basis_count == 3 &&
|
||||
!NEAR_ZERO(DIST_PNT_PLANE(candidate, basis_plane),
|
||||
tol->dist)) {
|
||||
have_volume = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
int all_planes_used = 1;
|
||||
for (size_t face = 0; face < plane_count; face++) {
|
||||
if (!plane_used[face]) {
|
||||
all_planes_used = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bu_free(plane_used, "inside plane use flags");
|
||||
return all_planes_used && have_volume;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +238,7 @@ arb7in(struct ged *gedp,
|
||||
planes[i][W] -= thick[i];
|
||||
}
|
||||
|
||||
if (!arb_in_planes_valid(planes, tol)) {
|
||||
if (!in_planes_valid((const plane_t *)planes, ARB_FACE_COUNT, tol)) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Cannot find a valid inside arb7: thicknesses eliminate a face or collapse the volume\n");
|
||||
return BRLCAD_ERROR;
|
||||
@@ -250,6 +261,43 @@ arb7in(struct ged *gedp,
|
||||
}
|
||||
|
||||
|
||||
/* Offset each outward-facing ARBN plane toward the interior. */
|
||||
static int
|
||||
arbnin(struct ged *gedp, struct rt_db_internal *ip, const fastf_t *thick,
|
||||
const struct bn_tol *tol)
|
||||
{
|
||||
struct rt_arbn_internal *arbn =
|
||||
(struct rt_arbn_internal *)ip->idb_ptr;
|
||||
RT_ARBN_CK_MAGIC(arbn);
|
||||
|
||||
plane_t *planes = (plane_t *)bu_calloc(arbn->neqn, sizeof(plane_t),
|
||||
"inside ARBN planes");
|
||||
for (size_t i = 0; i < arbn->neqn; i++) {
|
||||
fastf_t normal_length = MAGNITUDE(arbn->eqn[i]);
|
||||
if (!isfinite(normal_length) || normal_length <= SQRT_SMALL_FASTF) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Cannot find a valid inside ARBN: plane %zu has an invalid normal\n",
|
||||
i);
|
||||
bu_free(planes, "inside ARBN planes");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
HSCALE(planes[i], arbn->eqn[i], 1.0 / normal_length);
|
||||
planes[i][W] -= thick[i];
|
||||
}
|
||||
|
||||
if (!in_planes_valid((const plane_t *)planes, arbn->neqn, tol)) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Cannot find a valid inside ARBN: thicknesses eliminate a face or collapse the volume\n");
|
||||
bu_free(planes, "inside ARBN planes");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
bu_free(arbn->eqn, "arbn planes");
|
||||
arbn->eqn = planes;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
/* finds inside arbs */
|
||||
static int
|
||||
arbin(struct ged *gedp,
|
||||
@@ -925,12 +973,22 @@ ged_inside_internal(struct ged *gedp, struct rt_db_internal *ip, int argc, const
|
||||
if (ip->idb_type == ID_ARB8) {
|
||||
/* find the comgeom arb type, & reorganize */
|
||||
int uvec[8], svec[11];
|
||||
int issues = 0;
|
||||
struct bu_vls error_msg = BU_VLS_INIT_ZERO;
|
||||
|
||||
if (rt_arb_get_cgtype(&cgtype, (struct rt_arb_internal *)ip->idb_ptr, &wdbp->wdb_tol, uvec, svec) == 0) {
|
||||
bu_vls_printf(gedp->ged_result_str, "%s: BAD ARB\n", o_name);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
(void)rt_arb_validate(NULL,
|
||||
(const struct rt_arb_internal *)ip->idb_ptr,
|
||||
&wdbp->wdb_tol, &issues);
|
||||
if (issues & RT_ARB_VALIDATE_CONCAVE) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"%s: inside requires a convex ARB; concave ARB8 solids are unsupported\n",
|
||||
o_name);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
/* must find new plane equations to account for
|
||||
* any editing in the es_mat matrix or path to this solid.
|
||||
@@ -1008,6 +1066,30 @@ ged_inside_internal(struct ged *gedp, struct rt_db_internal *ip, int argc, const
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_ARBN: {
|
||||
struct rt_arbn_internal *arbn =
|
||||
(struct rt_arbn_internal *)ip->idb_ptr;
|
||||
RT_ARBN_CK_MAGIC(arbn);
|
||||
|
||||
size_t supplied = argc > arg ? (size_t)(argc - arg) : 0;
|
||||
if (supplied < arbn->neqn) {
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Enter thickness for plane P%zu: ", supplied);
|
||||
return GED_MORE;
|
||||
}
|
||||
|
||||
fastf_t *arbn_thick = (fastf_t *)bu_calloc(arbn->neqn,
|
||||
sizeof(fastf_t), "inside ARBN thicknesses");
|
||||
for (i = 0; i < arbn->neqn; i++)
|
||||
arbn_thick[i] = atof(argv[arg++]) * gedp->dbip->dbi_local2base;
|
||||
|
||||
int inside_result = arbnin(gedp, ip, arbn_thick, &wdbp->wdb_tol);
|
||||
bu_free(arbn_thick, "inside ARBN thicknesses");
|
||||
if (inside_result != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_TGC:
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (argc < arg+1) {
|
||||
|
||||
@@ -1926,6 +1926,19 @@ densities_prep(struct ged *gedp, struct rt_i *rtip)
|
||||
}
|
||||
FOR_ALL_DIRECTORY_END;
|
||||
}
|
||||
|
||||
// validation loop - all regions with a material ID should be in the density table
|
||||
struct region *regp = REGION_NULL;
|
||||
for (BU_LIST_FOR(regp, region, &(rtip->HeadRegion))) {
|
||||
const long int material_id = regp->reg_gmater;
|
||||
if (analyze_densities_density(_gd_densities, material_id) >= 0.0)
|
||||
continue;
|
||||
|
||||
bu_vls_printf(gedp->ged_result_str,
|
||||
"Error: Density %ld on region %s is not defined in the density table.\n", material_id, regp->reg_name);
|
||||
analyze_densities_clear(_gd_densities);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return BRLCAD_OK;
|
||||
|
||||
+90
-70
@@ -247,19 +247,41 @@ rt_in_rpp(struct xray *rp,
|
||||
}
|
||||
|
||||
|
||||
/* A name alone cannot distinguish transformed instances of a solid. */
|
||||
static struct soltab *
|
||||
rt_find_solid_with_mat(const struct rt_i *rtip,
|
||||
const struct directory *dp, const mat_t mat)
|
||||
{
|
||||
struct soltab *stp;
|
||||
|
||||
RT_VISIT_ALL_SOLTABS_START(stp, (struct rt_i *)rtip) {
|
||||
if (stp->st_dp != dp)
|
||||
continue;
|
||||
const fastf_t *st_mat = stp->st_matp ?
|
||||
stp->st_matp : bn_mat_identity;
|
||||
if (bn_mat_is_equal(mat, st_mat, &rtip->rti_tol))
|
||||
return stp;
|
||||
} RT_VISIT_ALL_SOLTABS_END;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Traverse the passed tree using rt_db_internals to show the way
|
||||
* This function supports rt_bound_internal and is internal to librt
|
||||
* Traverse the original database tree while tracking member transforms.
|
||||
*
|
||||
* Returns -
|
||||
* 0 success
|
||||
* -1 failure (tree_min and tree_max may have been altered)
|
||||
* Returns 0 on success, -1 if no bounds can be computed.
|
||||
*/
|
||||
int
|
||||
rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fastf_t *tree_max)
|
||||
static int
|
||||
rt_traverse_tree_mat(struct rt_i *rtip, const union tree *tp,
|
||||
fastf_t *tree_min, fastf_t *tree_max,
|
||||
const mat_t mat)
|
||||
{
|
||||
vect_t r_min, r_max; /* rpp for right side of tree */
|
||||
|
||||
if (!tp)
|
||||
return -1;
|
||||
|
||||
RT_CK_TREE(tp);
|
||||
|
||||
switch (tp->tr_op) {
|
||||
@@ -269,6 +291,8 @@ rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fas
|
||||
const struct soltab *stp;
|
||||
|
||||
stp = tp->tr_a.tu_stp;
|
||||
if (!stp)
|
||||
return -1;
|
||||
RT_CK_SOLTAB(stp);
|
||||
if (stp->st_aradius <= 0) {
|
||||
bu_log("rt_traverse_tree: encountered dead solid '%s'\n",
|
||||
@@ -293,16 +317,20 @@ rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fas
|
||||
case OP_XOR:
|
||||
case OP_UNION:
|
||||
/* BINARY type -- expand to contain both */
|
||||
if (rt_traverse_tree(rtip, tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
|
||||
rt_traverse_tree(rtip, tp->tr_b.tb_right, r_min, r_max) < 0)
|
||||
if (rt_traverse_tree_mat(rtip, tp->tr_b.tb_left,
|
||||
tree_min, tree_max, mat) < 0 ||
|
||||
rt_traverse_tree_mat(rtip, tp->tr_b.tb_right,
|
||||
r_min, r_max, mat) < 0)
|
||||
return -1;
|
||||
VMIN(tree_min, r_min);
|
||||
VMAX(tree_max, r_max);
|
||||
break;
|
||||
case OP_INTERSECT:
|
||||
/* BINARY type -- find common area only */
|
||||
if (rt_traverse_tree(rtip, tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
|
||||
rt_traverse_tree(rtip, tp->tr_b.tb_right, r_min, r_max) < 0)
|
||||
if (rt_traverse_tree_mat(rtip, tp->tr_b.tb_left,
|
||||
tree_min, tree_max, mat) < 0 ||
|
||||
rt_traverse_tree_mat(rtip, tp->tr_b.tb_right,
|
||||
r_min, r_max, mat) < 0)
|
||||
return -1;
|
||||
/* min = largest min, max = smallest max */
|
||||
VMAX(tree_min, r_min);
|
||||
@@ -313,7 +341,8 @@ rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fas
|
||||
* rt_gettree's subtractor shaker may have already discarded a
|
||||
* disjoint B (and its soltab) from the prepared tree, while this
|
||||
* routine may be walking the original database tree. */
|
||||
if (rt_traverse_tree(rtip, tp->tr_b.tb_left, tree_min, tree_max) < 0)
|
||||
if (rt_traverse_tree_mat(rtip, tp->tr_b.tb_left,
|
||||
tree_min, tree_max, mat) < 0)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
@@ -324,6 +353,8 @@ rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fas
|
||||
case OP_DB_LEAF:
|
||||
{
|
||||
const struct soltab *stp;
|
||||
struct directory *dp;
|
||||
mat_t leaf_mat;
|
||||
|
||||
if (rtip == NULL) {
|
||||
bu_log("rt_traverse_tree: A valid rtip was not passed for calculating bounds of '%s'\n",
|
||||
@@ -331,60 +362,44 @@ rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fas
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Good to go */
|
||||
MAT_COPY(leaf_mat, mat);
|
||||
if (tp->tr_l.tl_mat)
|
||||
bn_mat_mul(leaf_mat, mat, tp->tr_l.tl_mat);
|
||||
|
||||
/* Attempt to get a solid pointer, will fail for combs */
|
||||
stp = rt_find_solid(rtip, tp->tr_l.tl_name);
|
||||
dp = db_lookup(rtip->rti_dbip, tp->tr_l.tl_name,
|
||||
LOOKUP_QUIET);
|
||||
if (dp == RT_DIR_NULL)
|
||||
return -1;
|
||||
|
||||
stp = rt_find_solid_with_mat(rtip, dp, leaf_mat);
|
||||
if (stp == NULL) {
|
||||
|
||||
/* It was a comb! get an internal format and
|
||||
* repeat the whole thing that got us here in the
|
||||
* 1st place
|
||||
*/
|
||||
/* Recurse through combinations using their original
|
||||
* trees. A primitive without a matching prepared
|
||||
* instance has no valid bounds. */
|
||||
struct rt_db_internal intern;
|
||||
struct directory *dp;
|
||||
struct rt_comb_internal *combp;
|
||||
|
||||
/* Get the directory pointer */
|
||||
if ((dp=db_lookup(rtip->rti_dbip, tp->tr_l.tl_name, LOOKUP_QUIET)) == RT_DIR_NULL) {
|
||||
bu_log("rt_traverse_tree: db_lookup(%s) failed", tp->tr_l.tl_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Why does recursion work with the internal
|
||||
* format ? The internal format does have the
|
||||
* boolean op for a comb in the tr_a.tu_op field
|
||||
* in the root node, even though it has no prims
|
||||
* at the leaves. So recursive calls to load the
|
||||
* prim further down the tree, will return the
|
||||
* correct bb as we are going through the proper
|
||||
* switch case in each step down the tree
|
||||
*/
|
||||
if (!rt_db_lookup_internal(rtip->rti_dbip, tp->tr_l.tl_name, &dp, &intern, LOOKUP_NOISY)) {
|
||||
bu_log("rt_traverse_tree: rt_db_lookup_internal(%s) failed to get the internal form",
|
||||
tp->tr_l.tl_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The passed rt_db_internal should be a comb,
|
||||
* prepare a rt_comb_internal
|
||||
*/
|
||||
if (intern.idb_minor_type == ID_COMBINATION) {
|
||||
combp = (struct rt_comb_internal *)intern.idb_ptr;
|
||||
} else {
|
||||
/* if it's not a comb, then something else is
|
||||
* cooking.
|
||||
*/
|
||||
bu_log("rt_traverse_tree: WARNING : rt_db_lookup_internal(%s) got the internal form of a primitive when it should not, the bounds may not be correct", tp->tr_l.tl_name);
|
||||
if (intern.idb_minor_type != ID_COMBINATION) {
|
||||
bu_log("rt_traverse_tree: no prepared instance"
|
||||
" for '%s'\n", tp->tr_l.tl_name);
|
||||
rt_db_free_internal(&intern);
|
||||
return -1;
|
||||
}
|
||||
|
||||
combp = (struct rt_comb_internal *)intern.idb_ptr;
|
||||
RT_CK_COMB(combp);
|
||||
/* further down the rabbit hole */
|
||||
if (rt_traverse_tree(rtip, combp->tree, tree_min, tree_max)) {
|
||||
bu_log("rt_traverse_tree: rt_bound_tree() failed\n");
|
||||
int ret = rt_traverse_tree_mat(rtip, combp->tree,
|
||||
tree_min, tree_max, leaf_mat);
|
||||
rt_db_free_internal(&intern);
|
||||
if (ret)
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* Got a solid pointer, get bounds and return */
|
||||
RT_CK_SOLTAB(stp);
|
||||
@@ -408,13 +423,24 @@ rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fas
|
||||
}
|
||||
|
||||
case OP_NOP:
|
||||
/* Implies that this tree has nothing in it */
|
||||
break;
|
||||
/* An empty tree has no bounds to return. */
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rt_traverse_tree(struct rt_i *rtip, const union tree *tp,
|
||||
fastf_t *tree_min, fastf_t *tree_max)
|
||||
{
|
||||
mat_t mat;
|
||||
|
||||
MAT_IDN(mat);
|
||||
return rt_traverse_tree_mat(rtip, tp, tree_min, tree_max, mat);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rt_bound_instance(point_t *bmin, point_t *bmax,
|
||||
struct directory *dp,
|
||||
@@ -472,7 +498,8 @@ rt_bound_internal(struct db_i *dbip, struct directory *dp,
|
||||
struct rt_db_internal intern;
|
||||
struct rt_comb_internal *combp;
|
||||
vect_t tree_min, tree_max;
|
||||
union tree *tp;
|
||||
const union tree *tp;
|
||||
union tree primitive_tree;
|
||||
|
||||
/* Initialize RPP bounds */
|
||||
VSETALL(rpp_min, MAX_FASTF);
|
||||
@@ -494,7 +521,8 @@ rt_bound_internal(struct db_i *dbip, struct directory *dp,
|
||||
|
||||
|
||||
if (!rt_db_lookup_internal(dbip, dp->d_namep, &dp, &intern, LOOKUP_NOISY)) {
|
||||
bu_exit(1, "rt_bound_internal: rt_db_lookup_internal(%s) failed to get the internal form", dp->d_namep);
|
||||
bu_log("rt_bound_internal: lookup failed for '%s'\n",
|
||||
dp->d_namep);
|
||||
rt_i_destroy(rtip);
|
||||
return -1;
|
||||
}
|
||||
@@ -504,26 +532,18 @@ rt_bound_internal(struct db_i *dbip, struct directory *dp,
|
||||
*/
|
||||
if (intern.idb_minor_type == ID_COMBINATION) {
|
||||
combp = (struct rt_comb_internal *)intern.idb_ptr;
|
||||
RT_CK_COMB(combp);
|
||||
tp = combp->tree;
|
||||
} else {
|
||||
/* A primitive was passed, construct a struct rt_comb_internal
|
||||
* with a single leaf node.
|
||||
*/
|
||||
BU_ALLOC(combp, struct rt_comb_internal);
|
||||
RT_COMB_INTERNAL_INIT(combp);
|
||||
combp->region_flag = 0;
|
||||
|
||||
BU_GET(tp, union tree);
|
||||
RT_TREE_INIT(tp);
|
||||
tp->tr_l.tl_op = OP_SOLID;
|
||||
tp->tr_l.tl_name = bu_strdup("dummy");
|
||||
tp->tr_l.tl_mat = (matp_t)NULL;
|
||||
tp->tr_a.tu_stp = rt_find_solid(rtip, dp->d_namep);
|
||||
combp->tree = tp;
|
||||
/* A primitive uses its prepared solid directly. */
|
||||
RT_TREE_INIT(&primitive_tree);
|
||||
primitive_tree.tr_l.tl_op = OP_SOLID;
|
||||
primitive_tree.tr_a.tu_stp = rt_find_solid(rtip, dp->d_namep);
|
||||
tp = &primitive_tree;
|
||||
}
|
||||
|
||||
RT_CK_COMB(combp);
|
||||
if (rt_traverse_tree(rtip, combp->tree, tree_min, tree_max)) {
|
||||
bu_log("rt_bound_internal: rt_bound_tree() failed\n");
|
||||
if (rt_traverse_tree(rtip, tp, tree_min, tree_max)) {
|
||||
bu_log("rt_bound_internal: tree traversal failed\n");
|
||||
rt_db_free_internal(&intern);
|
||||
rt_i_destroy(rtip);
|
||||
return -1;
|
||||
|
||||
+17
-4
@@ -341,7 +341,7 @@ cache_init(struct rt_cache *cache)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static int
|
||||
compress_external(const struct rt_cache *cache, struct bu_external *external)
|
||||
{
|
||||
int ret;
|
||||
@@ -352,8 +352,16 @@ compress_external(const struct rt_cache *cache, struct bu_external *external)
|
||||
|
||||
BU_CK_EXTERNAL(external);
|
||||
|
||||
BU_ASSERT(external->ext_nbytes < INT_MAX);
|
||||
if (external->ext_nbytes >= INT_MAX) {
|
||||
CACHE_DEBUG("++++++ [%lu.%lu] Compression input is too large (%zu bytes)\n", bu_pid(), bu_parallel_id(), external->ext_nbytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
compressed_size = brl_LZ4_compressBound((int)external->ext_nbytes);
|
||||
if (compressed_size <= 0) {
|
||||
CACHE_DEBUG("++++++ [%lu.%lu] Compression input is unsupported (%zu bytes)\n", bu_pid(), bu_parallel_id(), external->ext_nbytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* buffer is uncompsize + maxcompsize + compressed_data */
|
||||
buffer = (uint8_t *)bu_malloc((size_t)compressed_size + SIZEOF_NETWORK_LONG, "buffer");
|
||||
@@ -367,12 +375,14 @@ compress_external(const struct rt_cache *cache, struct bu_external *external)
|
||||
|
||||
if (!compressed) {
|
||||
CACHE_DEBUG("++++++ [%lu.%lu] Compression failed (ret %d, %zu bytes @ %p to %d bytes max)\n", bu_pid(), bu_parallel_id(), ret, external->ext_nbytes, (void *) external->ext_buf, compressed_size);
|
||||
return;
|
||||
bu_free(buffer, "buffer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bu_free(external->ext_buf, "ext_buf");
|
||||
external->ext_nbytes = compressed_size + SIZEOF_NETWORK_LONG;
|
||||
external->ext_buf = buffer;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -569,7 +579,10 @@ cache_try_store(struct rt_cache *cache, const char *name, const struct rt_db_int
|
||||
return 0; /* can't serialize */
|
||||
}
|
||||
|
||||
compress_external(cache, &data_external);
|
||||
if (!compress_external(cache, &data_external)) {
|
||||
bu_free_external(&data_external);
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
struct bu_attribute_value_set attributes = BU_AVS_INIT_ZERO;
|
||||
|
||||
@@ -1914,8 +1914,19 @@ rt_edit_arb_edit(struct rt_edit *s)
|
||||
int arb_type = rt_arb_edit_type(s->log_str, s, arb, 0, s->tol);
|
||||
if (arb_type == 0)
|
||||
return BRLCAD_ERROR;
|
||||
if (rt_arb_calc_planes(&error_msg, arb, arb_type, a->es_peqn, s->tol)) {
|
||||
bu_vls_printf(s->log_str, "\nCannot calculate plane equations for ARB8\n");
|
||||
|
||||
int validation_issues = 0;
|
||||
(void)rt_arb_validate(NULL, arb, s->tol, &validation_issues);
|
||||
int planes_valid = !(validation_issues & RT_ARB_VALIDATE_NONCOPLANAR) &&
|
||||
!rt_arb_calc_planes(&error_msg, arb, arb_type, a->es_peqn, s->tol);
|
||||
int planes_required = s->edit_flag == ECMD_ARB_MOVE_FACE ||
|
||||
s->edit_flag == ECMD_ARB_SETUP_ROTFACE ||
|
||||
s->edit_flag == ECMD_ARB_ROTATE_FACE ||
|
||||
s->edit_flag == PTARB || s->edit_flag == EARB;
|
||||
if (!planes_valid && planes_required) {
|
||||
bu_vls_printf(s->log_str,
|
||||
"Cannot edit ARB faces or edges without valid face planes: %s",
|
||||
bu_vls_cstr(&error_msg));
|
||||
bu_vls_free(&error_msg);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
@@ -1937,11 +1948,11 @@ rt_edit_arb_edit(struct rt_edit *s)
|
||||
break;
|
||||
case ECMD_ARB_MAIN_MENU:
|
||||
ecmd_arb_main_menu(s);
|
||||
break;
|
||||
return BRLCAD_OK;
|
||||
case ECMD_ARB_SPECIFIC_MENU:
|
||||
if (ecmd_arb_specific_menu(s) != BRLCAD_OK)
|
||||
return -1;
|
||||
break;
|
||||
return BRLCAD_OK;
|
||||
case ECMD_ARB_MOVE_FACE:
|
||||
return ecmd_arb_move_face(s);
|
||||
case ECMD_ARB_SETUP_ROTFACE:
|
||||
@@ -1980,6 +1991,11 @@ arb_planecalc:
|
||||
|
||||
if (ret != BRLCAD_OK)
|
||||
goto arb_failed;
|
||||
/* Rigid and uniform whole-solid transforms preserve an invalid ARB's
|
||||
* shape. They must remain usable even when face-specific editing cannot
|
||||
* construct a complete set of planes. */
|
||||
if (!planes_valid)
|
||||
return ret;
|
||||
if (edarb_canonicalize(s, arb) != BRLCAD_OK) {
|
||||
goto arb_failed;
|
||||
}
|
||||
|
||||
@@ -235,6 +235,7 @@ rt_edit_bot_labels(
|
||||
VADD3(mid_pt, p1, p2, p3);
|
||||
|
||||
VSCALE(mid_pt, mid_pt, one_third);
|
||||
POINT_LABEL_STR(mid_pt, "face");
|
||||
|
||||
*num_lines = 3;
|
||||
VMOVE(lines[0], mid_pt);
|
||||
@@ -1114,8 +1115,7 @@ ecmd_bot_pickt(struct rt_edit *s, const vect_t mousevec)
|
||||
b->bot_verts[1] = -1;
|
||||
b->bot_verts[2] = -1;
|
||||
bu_vls_free(&vls);
|
||||
}
|
||||
if (hits == 1) {
|
||||
} else if (hits == 1) {
|
||||
sscanf(bu_vls_cstr(&vls), " { { %d %d %d", &b->bot_verts[0], &b->bot_verts[1], &b->bot_verts[2]);
|
||||
bu_vls_free(&vls);
|
||||
} else {
|
||||
|
||||
@@ -270,10 +270,12 @@ rt_hlf_norm(register struct hit *hitp, struct soltab *stp, register struct xray
|
||||
/* We are expected to compute hit_point here. May be infinite. */
|
||||
f = hitp->hit_dist;
|
||||
if (f <= -INFINITY) {
|
||||
bu_log("rt_hlf_norm: hit_dist = -INFINITY, unable to compute pt.\n");
|
||||
if (RT_G_DEBUG & RT_DEBUG_ARB8)
|
||||
bu_log("rt_hlf_norm: hit_dist = -INFINITY, unable to compute pt.\n");
|
||||
VSETALL(hitp->hit_point, -INFINITY);
|
||||
} else if (f >= INFINITY) {
|
||||
bu_log("rt_hlf_norm: hit_dist = +INFINITY, unable to compute pt.\n");
|
||||
if (RT_G_DEBUG & RT_DEBUG_ARB8)
|
||||
bu_log("rt_hlf_norm: hit_dist = +INFINITY, unable to compute pt.\n");
|
||||
VSETALL(hitp->hit_point, INFINITY);
|
||||
} else {
|
||||
VJOIN1(hitp->hit_point, rp->r_pt, f, rp->r_dir);
|
||||
|
||||
@@ -1732,7 +1732,7 @@ rt_hyp_volume(fastf_t *volume, const struct rt_db_internal *ip)
|
||||
C_DECL int
|
||||
rt_hyp_labels(struct rt_point_labels *pl, int pl_max, const mat_t xform, const struct rt_db_internal *ip, const struct bn_tol *UNUSED(tol))
|
||||
{
|
||||
int lcnt = 4;
|
||||
int lcnt = 5;
|
||||
if (!pl || pl_max < lcnt || !ip)
|
||||
return 0;
|
||||
|
||||
@@ -1767,6 +1767,13 @@ rt_hyp_labels(struct rt_point_labels *pl, int pl_max, const mat_t xform, const s
|
||||
MAT4X3PNT(pos_view, xform, work);
|
||||
POINT_LABEL(pos_view, 'B');
|
||||
|
||||
/* hyp_bnr is the neck-to-base ratio. Show it at the neck's
|
||||
* semi-major-axis point, halfway along H. */
|
||||
VJOIN2(work, hyp->hyp_Vi, 0.5, hyp->hyp_Hi,
|
||||
hyp->hyp_bnr, hyp->hyp_A);
|
||||
MAT4X3PNT(pos_view, xform, work);
|
||||
POINT_LABEL(pos_view, 'c');
|
||||
|
||||
return lcnt;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,10 +72,15 @@ brlcad_add_test(NAME rt_tree_prune COMMAND rt_tree_prune)
|
||||
|
||||
brlcad_addexec(rt_reprep_prune reprep_prune.c "librt;libwdb;libbu;${M_LIBRARY}" TEST)
|
||||
|
||||
brlcad_addexec(rt_rtcmp_capture rtcmp_capture.c "librt;libwdb;libbu;${M_LIBRARY}" TEST)
|
||||
brlcad_add_test(NAME rt_rtcmp_capture COMMAND rt_rtcmp_capture)
|
||||
brlcad_add_test(NAME rt_rtcmp_capture_primitives COMMAND rt_rtcmp_capture primitives)
|
||||
brlcad_add_test(NAME rt_reprep_prune COMMAND rt_reprep_prune)
|
||||
# Note - this feature is not available in a BRLCAD_ENABLE_RUNTIME_DEBUG=OFF
|
||||
# build, since it has an unavoidable performance overhead in the hot loop to
|
||||
# check if the setting is enabled.
|
||||
if (BRLCAD_ENABLE_RUNTIME_DEBUG)
|
||||
brlcad_addexec(rt_rtcmp_capture rtcmp_capture.c "librt;libwdb;libbu;${M_LIBRARY}" TEST)
|
||||
brlcad_add_test(NAME rt_rtcmp_capture COMMAND rt_rtcmp_capture)
|
||||
brlcad_add_test(NAME rt_rtcmp_capture_primitives COMMAND rt_rtcmp_capture primitives)
|
||||
brlcad_add_test(NAME rt_reprep_prune COMMAND rt_reprep_prune)
|
||||
endif()
|
||||
|
||||
brlcad_addexec(rt_submodel_xform submodel_xform.c "librt;libwdb;libbu;${M_LIBRARY}" TEST)
|
||||
brlcad_add_test(NAME rt_submodel_xform COMMAND rt_submodel_xform)
|
||||
@@ -212,36 +217,37 @@ brlcad_add_test(NAME rt_metaball_adjust COMMAND rt_metaball_adjust)
|
||||
set(
|
||||
distcheck_files
|
||||
CMakeLists.txt
|
||||
ars_inside.c
|
||||
arb_intersect.g
|
||||
ars_inside.c
|
||||
binary_attribute.c
|
||||
binunif.c
|
||||
brep_io.cpp
|
||||
bound_internal.c
|
||||
brep_boolean_tests.g
|
||||
brep_io.cpp
|
||||
crofton.c
|
||||
cyclic_tests.g
|
||||
datum_annot_semantics.c
|
||||
db_name.c
|
||||
default_object.c
|
||||
datum_annot_semantics.c
|
||||
dsp_raytrace_check.c
|
||||
dsp_sa_vol_check.c
|
||||
primitive_brep.cpp
|
||||
reprep_prune.c
|
||||
brep_boolean_tests.g
|
||||
cyclic_tests.g
|
||||
extreme_ssi_test.g
|
||||
invalid_inmem.c
|
||||
lcomb_large.c
|
||||
matrix_tests.g
|
||||
metaball_adjust.c
|
||||
nurbs_surfaces.g
|
||||
pnts_bounds.c
|
||||
prim_tess.c
|
||||
primitive_brep.cpp
|
||||
reprep_prune.c
|
||||
rt_datum.c
|
||||
rt_perturb.c
|
||||
rtcmp_capture.c
|
||||
search_stress.c
|
||||
static_init.cpp
|
||||
sketch.g
|
||||
static_init.cpp
|
||||
submodel_xform.c
|
||||
prim_tess.c
|
||||
pnts_bounds.c
|
||||
tess_timing.c
|
||||
tree_prune.c
|
||||
vds_tree.c
|
||||
|
||||
@@ -37,6 +37,7 @@ main(int UNUSED(argc), const char **argv)
|
||||
point_t bmin, bmax;
|
||||
point_t expected_min = {-1.0, -1.0, -1.0};
|
||||
point_t expected_max = { 1.0, 1.0, 1.0};
|
||||
mat_t translated;
|
||||
int ret = 1;
|
||||
|
||||
bu_setprogname(argv[0]);
|
||||
@@ -75,6 +76,68 @@ main(int UNUSED(argc), const char **argv)
|
||||
if (!VNEAR_EQUAL(bmax, expected_max, BN_TOL_DIST))
|
||||
goto done;
|
||||
|
||||
dp = db_lookup(dbip, "left.s", LOOKUP_QUIET);
|
||||
if (dp == RT_DIR_NULL || rt_bound_internal(dbip, dp, bmin, bmax))
|
||||
goto done;
|
||||
if (!VNEAR_EQUAL(bmin, expected_min, BN_TOL_DIST) ||
|
||||
!VNEAR_EQUAL(bmax, expected_max, BN_TOL_DIST))
|
||||
goto done;
|
||||
|
||||
BU_LIST_INIT(&wm.l);
|
||||
if (mk_comb(wdbp, "empty.c", &wm.l, 0, NULL, NULL, NULL,
|
||||
0, 0, 0, 0, 0, 0, 0))
|
||||
goto done;
|
||||
dp = db_lookup(dbip, "empty.c", LOOKUP_QUIET);
|
||||
if (dp == RT_DIR_NULL ||
|
||||
rt_bound_internal(dbip, dp, bmin, bmax) == 0)
|
||||
goto done;
|
||||
|
||||
BU_LIST_INIT(&wm.l);
|
||||
if (!mk_addmember("empty.c", &wm.l, NULL, WMOP_UNION))
|
||||
goto done;
|
||||
if (mk_lcomb(wdbp, "nested.c", &wm, 0, NULL, NULL, NULL, 0))
|
||||
goto done;
|
||||
dp = db_lookup(dbip, "nested.c", LOOKUP_QUIET);
|
||||
if (dp == RT_DIR_NULL ||
|
||||
rt_bound_internal(dbip, dp, bmin, bmax) == 0)
|
||||
goto done;
|
||||
|
||||
MAT_IDN(translated);
|
||||
MAT_DELTAS(translated, 20.0, 0.0, 0.0);
|
||||
BU_LIST_INIT(&wm.l);
|
||||
if (!mk_addmember("left.s", &wm.l, NULL, WMOP_UNION) ||
|
||||
!mk_addmember("left.s", &wm.l, translated, WMOP_UNION))
|
||||
goto done;
|
||||
if (mk_lcomb(wdbp, "instanced.r", &wm, 1, NULL, NULL, NULL, 0))
|
||||
goto done;
|
||||
dp = db_lookup(dbip, "instanced.r", LOOKUP_QUIET);
|
||||
if (dp == RT_DIR_NULL || rt_bound_internal(dbip, dp, bmin, bmax))
|
||||
goto done;
|
||||
VSET(expected_max, 21.0, 1.0, 1.0);
|
||||
if (!VNEAR_EQUAL(bmin, expected_min, BN_TOL_DIST) ||
|
||||
!VNEAR_EQUAL(bmax, expected_max, BN_TOL_DIST))
|
||||
goto done;
|
||||
|
||||
BU_LIST_INIT(&wm.l);
|
||||
if (!mk_addmember("left.s", &wm.l, translated, WMOP_UNION))
|
||||
goto done;
|
||||
if (mk_lcomb(wdbp, "child.c", &wm, 0, NULL, NULL, NULL, 0))
|
||||
goto done;
|
||||
MAT_DELTAS(translated, 10.0, 0.0, 0.0);
|
||||
BU_LIST_INIT(&wm.l);
|
||||
if (!mk_addmember("child.c", &wm.l, translated, WMOP_UNION))
|
||||
goto done;
|
||||
if (mk_lcomb(wdbp, "parent.r", &wm, 1, NULL, NULL, NULL, 0))
|
||||
goto done;
|
||||
dp = db_lookup(dbip, "parent.r", LOOKUP_QUIET);
|
||||
if (dp == RT_DIR_NULL || rt_bound_internal(dbip, dp, bmin, bmax))
|
||||
goto done;
|
||||
VSET(expected_min, 29.0, -1.0, -1.0);
|
||||
VSET(expected_max, 31.0, 1.0, 1.0);
|
||||
if (!VNEAR_EQUAL(bmin, expected_min, BN_TOL_DIST) ||
|
||||
!VNEAR_EQUAL(bmax, expected_max, BN_TOL_DIST))
|
||||
goto done;
|
||||
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
|
||||
@@ -343,6 +343,79 @@ test_arb_geometry_helpers(struct rt_edit *s, struct rt_arb_internal *arb,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nonplanar_arb8_reset(struct rt_edit *s, struct rt_arb_internal *arb,
|
||||
struct rt_arb8_edit *a, const struct bn_tol *tol)
|
||||
{
|
||||
arb8_reset(s, arb, a);
|
||||
arb->pt[6][Z] = 1.25;
|
||||
int issues = 0;
|
||||
(void)rt_arb_validate(NULL, arb, tol, &issues);
|
||||
if (!(issues & RT_ARB_VALIDATE_NONCOPLANAR))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 test fixture is planar\n");
|
||||
MAT_IDN(s->e_mat);
|
||||
MAT_IDN(s->e_invmat);
|
||||
MAT_IDN(s->model_changes);
|
||||
s->mv_context = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_nonplanar_whole_solid_edits(struct rt_edit *s,
|
||||
struct rt_arb_internal *arb, struct rt_arb8_edit *a,
|
||||
const struct bn_tol *tol)
|
||||
{
|
||||
nonplanar_arb8_reset(s, arb, a, tol);
|
||||
rt_edit_set_edflag(s, RT_PARAMS_EDIT_SCALE);
|
||||
s->es_scale = 2.0;
|
||||
VSETALL(s->e_keypoint, 0.0);
|
||||
if (rt_edit_process(s) != BRLCAD_OK) {
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid scale was rejected\n");
|
||||
}
|
||||
point_t scaled = {2.0, 2.0, 2.5};
|
||||
if (!VNEAR_EQUAL(arb->pt[6], scaled, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid scale failed\n");
|
||||
|
||||
nonplanar_arb8_reset(s, arb, a, tol);
|
||||
rt_edit_set_edflag(s, RT_PARAMS_EDIT_TRANS);
|
||||
s->e_inpara = 3;
|
||||
VSET(s->e_para, 2.0, 3.0, 4.0);
|
||||
VSETALL(s->e_keypoint, 0.0);
|
||||
if (rt_edit_process(s) != BRLCAD_OK) {
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid translation was rejected\n");
|
||||
}
|
||||
point_t translated = {3.0, 4.0, 5.25};
|
||||
if (!VNEAR_EQUAL(arb->pt[6], translated, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid translation failed\n");
|
||||
|
||||
nonplanar_arb8_reset(s, arb, a, tol);
|
||||
rt_edit_set_edflag(s, RT_PARAMS_EDIT_ROT);
|
||||
s->e_inpara = 3;
|
||||
VSET(s->e_para, 0.0, 0.0, 90.0);
|
||||
VSETALL(s->e_keypoint, 0.0);
|
||||
if (rt_edit_process(s) != BRLCAD_OK) {
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid rotation was rejected\n");
|
||||
}
|
||||
point_t rotated = {-1.0, 1.0, 1.25};
|
||||
if (!VNEAR_EQUAL(arb->pt[6], rotated, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 whole-solid rotation failed\n");
|
||||
|
||||
nonplanar_arb8_reset(s, arb, a, tol);
|
||||
struct rt_arb_internal before_face_move = *arb;
|
||||
a->edit_menu = 0;
|
||||
rt_edit_set_edflag(s, ECMD_ARB_MOVE_FACE);
|
||||
s->e_inpara = 3;
|
||||
VSET(s->e_para, 0.0, 0.0, 0.25);
|
||||
bu_vls_trunc(s->log_str, 0);
|
||||
if (rt_edit_process(s) != BRLCAD_ERROR ||
|
||||
memcmp(arb->pt, before_face_move.pt, sizeof(arb->pt)) ||
|
||||
!strstr(bu_vls_cstr(s->log_str), "valid face planes"))
|
||||
bu_exit(1, "ERROR: nonplanar ARB8 face edit was not rejected cleanly\n");
|
||||
|
||||
bu_log("Nonplanar ARB8 whole-solid edits SUCCESS\n");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rt_edit_test_arb8(void)
|
||||
{
|
||||
@@ -953,6 +1026,7 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
|
||||
bu_log("ECMD_ARB_ROTATE_FACE knob edit SUCCESS\n");
|
||||
|
||||
test_arb_geometry_helpers(s, arb, a, &tol);
|
||||
test_nonplanar_whole_solid_edits(s, arb, a, &tol);
|
||||
|
||||
/* The public editing entry point must reject invalid type and menu indexes
|
||||
* before using them to address the type-specific editing tables. */
|
||||
|
||||
@@ -643,6 +643,32 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
|
||||
be->bot_verts[0], be->bot_verts[1], be->bot_verts[2]);
|
||||
}
|
||||
|
||||
/* The selected face is labeled at its centroid and marked with one line
|
||||
* from the centroid to each vertex. */
|
||||
{
|
||||
struct rt_point_labels labels[3] = {RT_POINT_LABELS_INIT};
|
||||
point_t lines[2 * 4];
|
||||
mat_t identity;
|
||||
int num_lines = 0;
|
||||
MAT_IDN(identity);
|
||||
EDOBJ[ID_BOT].ft_labels(&num_lines, lines, labels, 3, identity, s, &tol);
|
||||
|
||||
point_t centroid = {1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0};
|
||||
point_t vertices[3] = {{1.0, 0.0, 0.0},
|
||||
{0.0, 1.0, 0.0},
|
||||
{0.0, 0.0, 1.0}};
|
||||
if (num_lines != 3 || !BU_STR_EQUAL(labels[0].str, "face") ||
|
||||
!VNEAR_EQUAL(labels[0].pt, centroid, VUNITIZE_TOL) ||
|
||||
!BU_STR_EQUAL(labels[1].str, "pt"))
|
||||
bu_exit(1, "ERROR: selected BOT face label is missing or misplaced\n");
|
||||
for (int i = 0; i < num_lines; ++i) {
|
||||
if (!VNEAR_EQUAL(lines[i * 2], centroid, VUNITIZE_TOL) ||
|
||||
!VNEAR_EQUAL(lines[i * 2 + 1], vertices[i], VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: selected BOT face marker line %d is misplaced\n", i);
|
||||
}
|
||||
bu_log("ECMD_BOT_PICKT label SUCCESS: face centroid is marked\n");
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* ECMD_BOT_MODE (descriptor path): set mode to RT_BOT_SOLID (2)
|
||||
* ================================================================*/
|
||||
|
||||
@@ -178,6 +178,20 @@ rt_edit_test_hyp(void)
|
||||
|
||||
vect_t mousevec;
|
||||
|
||||
{
|
||||
struct rt_point_labels labels[5] = {RT_POINT_LABELS_INIT};
|
||||
mat_t identity;
|
||||
MAT_IDN(identity);
|
||||
int label_count = OBJ[ID_HYP].ft_labels(labels, 5, identity,
|
||||
&s->es_int, &tol);
|
||||
point_t expected_c = {2.0, 0.0, 5.0};
|
||||
if (label_count != 5 || !BU_STR_EQUAL(labels[4].str, "c") ||
|
||||
!VNEAR_EQUAL(labels[4].pt, expected_c, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: HYP neck ratio label is missing or misplaced\n");
|
||||
bu_log("HYP neck ratio label SUCCESS: c=%g,%g,%g\n",
|
||||
V3ARGS(labels[4].pt));
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* ECMD_HYP_H (scale Hi; note: e_para[0] is es_scale, not |Hi|)
|
||||
* MGED: es_scale = e_para[0] (scale factor); Hi' = Hi * es_scale
|
||||
|
||||
@@ -85,6 +85,69 @@ proc exercise_object_lifecycle {class object args} {
|
||||
}
|
||||
}
|
||||
|
||||
proc exercise_panedwindow_bindings {} {
|
||||
set pane_size 200
|
||||
set drag_distance 20
|
||||
set native_motion_binding [bind Panedwindow <Motion>]
|
||||
|
||||
toplevel .panes
|
||||
foreach orientation {horizontal vertical} {
|
||||
set pane .panes.$orientation
|
||||
iwidgets::panedwindow $pane -orient $orientation \
|
||||
-width $pane_size -height $pane_size -showhandle 0
|
||||
$pane add first -minimum 0 -margin 0
|
||||
$pane add second -minimum 0 -margin 0
|
||||
pack $pane -side left -fill both -expand yes
|
||||
}
|
||||
|
||||
panedwindow .panes.native -width $pane_size -height $pane_size
|
||||
foreach name {first second} {
|
||||
frame .panes.native.$name
|
||||
.panes.native add .panes.native.$name
|
||||
}
|
||||
pack .panes.native -side left -fill both -expand yes
|
||||
update
|
||||
|
||||
# Hull events must not invoke native Tk handlers on Iwidgets objects.
|
||||
foreach pane {.panes.horizontal .panes.vertical .panes.native} {
|
||||
foreach event {
|
||||
<Motion> <Leave>
|
||||
<ButtonPress-1> <B1-Motion> <ButtonRelease-1>
|
||||
<ButtonPress-2> <B2-Motion> <ButtonRelease-2>
|
||||
} {
|
||||
event generate $pane $event -x 1 -y 1
|
||||
}
|
||||
update
|
||||
assert_equal "$pane pointer events" $::background_errors {}
|
||||
}
|
||||
assert_equal "native panedwindow motion binding" \
|
||||
[bind Panedwindow <Motion>] $native_motion_binding
|
||||
|
||||
# Removing the hull's class tag must retain Iwidgets' sash dragging.
|
||||
foreach orientation {horizontal vertical} {
|
||||
set pane .panes.$orientation
|
||||
set before [$pane fraction]
|
||||
set sash [$pane component sash1]
|
||||
set x 0
|
||||
set y 0
|
||||
if {$orientation eq "horizontal"} {
|
||||
set y $drag_distance
|
||||
} else {
|
||||
set x $drag_distance
|
||||
}
|
||||
event generate $sash <ButtonPress-1> -x 0 -y 0
|
||||
event generate $sash <B1-Motion> -x $x -y $y
|
||||
event generate $sash <B1-ButtonRelease-1> -x $x -y $y
|
||||
update
|
||||
if {[lindex [$pane fraction] 0] <= [lindex $before 0]} {
|
||||
fail "$orientation panedwindow sash did not move"
|
||||
}
|
||||
assert_equal "$orientation sash events" $::background_errors {}
|
||||
}
|
||||
destroy .panes
|
||||
update
|
||||
}
|
||||
|
||||
proc require_at_least {package minimum} {
|
||||
set version [package require $package $minimum]
|
||||
if {[package vcompare $version $minimum] < 0} {
|
||||
@@ -102,6 +165,7 @@ set tk_version [require_at_least Tk 8.6]
|
||||
set itcl_version [require_at_least Itcl 4.3.0]
|
||||
set itk_version [require_at_least Itk 4.2.3]
|
||||
set iwidgets_version [require_at_least Iwidgets 4.1.1]
|
||||
exercise_panedwindow_bindings
|
||||
interp alias {} Hierarchy {} ::iwidgets::Hierarchy
|
||||
interp alias {} scrolledlistbox {} ::iwidgets::scrolledlistbox
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ if(BRLCAD_ENABLE_TCL)
|
||||
if(TK_LIBRARY)
|
||||
target_compile_definitions(mged PRIVATE HAVE_TK=1)
|
||||
endif(TK_LIBRARY)
|
||||
target_include_directories(mged BEFORE PRIVATE ${MGED_INCLUDE_DIRS})
|
||||
brlcad_include_dirs(mged MGED_INCLUDE_DIRS PRIVATE)
|
||||
add_target_deps(mged Tkhtml Tktable itcl_pkgIndex itk_pkgIndex TclIndexBld dm_plugins)
|
||||
|
||||
# MGED needs the tclIndex and pkgIndex files set up correctly
|
||||
|
||||
+4
-2
@@ -425,6 +425,8 @@ mged_attach(struct mged_state *s, const char *wp_name, int argc, const char *arg
|
||||
{
|
||||
int opt_argc;
|
||||
char **opt_argv;
|
||||
const char *dm_name;
|
||||
const char *dm_lname;
|
||||
struct mged_dm *o_dm;
|
||||
|
||||
if (!wp_name) {
|
||||
@@ -495,8 +497,8 @@ mged_attach(struct mged_state *s, const char *wp_name, int argc, const char *arg
|
||||
mged_link_vars(s->mged_curr_dm);
|
||||
|
||||
Tcl_ResetResult(s->interp);
|
||||
const char *dm_name = dm_get_dm_name(DMP);
|
||||
const char *dm_lname = dm_get_dm_lname(DMP);
|
||||
dm_name = dm_get_dm_name(DMP);
|
||||
dm_lname = dm_get_dm_lname(DMP);
|
||||
if (dm_name && dm_lname) {
|
||||
Tcl_AppendResult(s->interp, "ATTACHING ", dm_name, " (", dm_lname, ")\n", (char *)NULL);
|
||||
}
|
||||
|
||||
+22
-55
@@ -424,11 +424,12 @@ ecmd_bot_pickt_multihit_clbk(int UNUSED(ac), const char **UNUSED(av), void *d, v
|
||||
struct rt_bot_edit *b = (struct rt_bot_edit *)se->ipe_ptr;
|
||||
struct bu_vls *vls = (struct bu_vls *)se->u_ptr;
|
||||
|
||||
// Evil Tcl variable linkage. Will need to figure out how to do this
|
||||
// "on the fly" with temporary s_edit structure internal variables...
|
||||
Tcl_LinkVar(s->interp, "bot_v1", (char *)&b->bot_verts[0], TCL_LINK_INT);
|
||||
Tcl_LinkVar(s->interp, "bot_v2", (char *)&b->bot_verts[1], TCL_LINK_INT);
|
||||
Tcl_LinkVar(s->interp, "bot_v3", (char *)&b->bot_verts[2], TCL_LINK_INT);
|
||||
/* The chooser is nonmodal, so it cannot safely retain links to this edit
|
||||
* state. Clear the old selection while the user chooses a new face; the
|
||||
* Tcl callback applies the chosen indices through the normal edit path. */
|
||||
b->bot_verts[0] = -1;
|
||||
b->bot_verts[1] = -1;
|
||||
b->bot_verts[2] = -1;
|
||||
|
||||
int ret_tcl = Tcl_VarEval(s->interp, "bot_face_select ", bu_vls_cstr(vls), (char *)NULL);
|
||||
int ret = BRLCAD_OK;
|
||||
@@ -439,9 +440,6 @@ ecmd_bot_pickt_multihit_clbk(int UNUSED(ac), const char **UNUSED(av), void *d, v
|
||||
b->bot_verts[2] = -1;
|
||||
ret = BRLCAD_ERROR;
|
||||
}
|
||||
Tcl_UnlinkVar(s->interp, "bot_v1");
|
||||
Tcl_UnlinkVar(s->interp, "bot_v2");
|
||||
Tcl_UnlinkVar(s->interp, "bot_v3");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -735,6 +733,7 @@ sedit_mouse(struct mged_state *s, const vect_t mousevec)
|
||||
if (bu_vls_strlen(MEDIT(s)->log_str)) {
|
||||
Tcl_AppendResult(s->interp, bu_vls_cstr(MEDIT(s)->log_str), (char *)NULL);
|
||||
bu_vls_trunc(MEDIT(s)->log_str, 0);
|
||||
mged_print_result(0, NULL, s, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1711,57 +1710,25 @@ f_sedit_reset(ClientData clientData, Tcl_Interp *interp, int argc, const char *U
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* free old copy */
|
||||
rt_db_free_internal(&MEDIT(s)->es_int);
|
||||
|
||||
/* reset internal variables */
|
||||
if (EDOBJ[MEDIT(s)->es_int.idb_type].ft_prim_edit_reset)
|
||||
(*EDOBJ[MEDIT(s)->es_int.idb_type].ft_prim_edit_reset)(MEDIT(s));
|
||||
|
||||
/* read in a fresh copy */
|
||||
if (!illump || !illump->s_u_data)
|
||||
if (!illump->s_u_data)
|
||||
return TCL_ERROR;
|
||||
|
||||
struct ged_bv_data *bdata = (struct ged_bv_data *)illump->s_u_data;
|
||||
if (rt_db_get_internal(&MEDIT(s)->es_int, LAST_SOLID(bdata),
|
||||
s->dbip, NULL) < 0) {
|
||||
if (bdata->s_fullpath.fp_len > 0) {
|
||||
Tcl_AppendResult(interp, "sedit_reset(",
|
||||
LAST_SOLID(bdata)->d_namep,
|
||||
"): solid import failure\n", (char *)NULL);
|
||||
} else {
|
||||
Tcl_AppendResult(interp, "sedit_reset(NULL): solid import failure\n", (char *)NULL);
|
||||
|
||||
}
|
||||
return TCL_ERROR; /* FAIL */
|
||||
if (!bdata->s_fullpath.fp_len) {
|
||||
Tcl_AppendResult(interp, "sedit_reset(NULL): solid import failure\n", (char *)NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
RT_CK_DB_INTERNAL(&MEDIT(s)->es_int);
|
||||
|
||||
struct directory *dp = LAST_SOLID(bdata);
|
||||
if (reinit_edit_state(s, bdata) != BRLCAD_OK) {
|
||||
Tcl_AppendResult(interp, "sedit_reset(",
|
||||
dp->d_namep,
|
||||
"): solid import failure\n", (char *)NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
init_sedit_vars(s);
|
||||
replot_editing_solid(0, NULL, s, NULL);
|
||||
|
||||
/* Establish initial keypoint */
|
||||
MEDIT(s)->e_keytag = "";
|
||||
rt_get_solid_keypoint(MEDIT(s), &MEDIT(s)->e_keypoint, &MEDIT(s)->e_keytag, MEDIT(s)->e_mat);
|
||||
|
||||
/* Reset relevant variables */
|
||||
MAT_IDN(MEDIT(s)->acc_rot_sol);
|
||||
VSETALL(MEDIT(s)->k.rot_m_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_o_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_v_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_m_abs_last, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_o_abs_last, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_v_abs_last, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_m_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_v_abs, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_m_abs_last, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_v_abs_last, 0.0);
|
||||
MEDIT(s)->k.sca_abs = 0.0;
|
||||
MEDIT(s)->acc_sc_sol = 1.0;
|
||||
VSETALL(MEDIT(s)->k.rot_m, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_o, 0.0);
|
||||
VSETALL(MEDIT(s)->k.rot_v, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_m, 0.0);
|
||||
VSETALL(MEDIT(s)->k.tra_v, 0.0);
|
||||
|
||||
set_e_axes_pos(s, 1);
|
||||
s->update_views = 1;
|
||||
dm_set_dirty(DMP, 1);
|
||||
|
||||
|
||||
+2
-1
@@ -86,6 +86,7 @@ f_facedef(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[
|
||||
struct rt_arb_internal *arb;
|
||||
struct rt_arb_internal *arbo;
|
||||
plane_t planes[6];
|
||||
int arb_type;
|
||||
int status;
|
||||
struct bu_vls error_msg;
|
||||
|
||||
@@ -125,7 +126,7 @@ f_facedef(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[
|
||||
RT_ARB_CK_MAGIC(arb);
|
||||
|
||||
/* find new planes to account for any editing */
|
||||
int arb_type = rt_arb_std_type(&MEDIT(s)->es_int, MEDIT(s)->tol);
|
||||
arb_type = rt_arb_std_type(&MEDIT(s)->es_int, MEDIT(s)->tol);
|
||||
if (rt_arb_calc_planes(&error_msg, arb, arb_type, planes, &s->tol.tol)) {
|
||||
Tcl_AppendResult(interp, bu_vls_addr(&error_msg),
|
||||
"Unable to determine plane equations\n", (char *)NULL);
|
||||
|
||||
@@ -113,9 +113,6 @@ extern struct _mged_variables default_mged_variables;
|
||||
/* defined in color_scheme.c */
|
||||
extern struct _color_scheme default_color_scheme;
|
||||
|
||||
/* defined in grid.c */
|
||||
extern struct bv_grid_state default_grid_state;
|
||||
|
||||
/* defined in axes.c */
|
||||
extern struct _axes_state default_axes_state;
|
||||
|
||||
|
||||
@@ -575,6 +575,7 @@ void pr_beep(void);
|
||||
void pr_prompt(struct mged_state *s);
|
||||
|
||||
/* grid.c */
|
||||
extern struct bv_grid_state default_grid_state;
|
||||
extern void round_to_grid(struct mged_state *s, fastf_t *view_dx, fastf_t *view_dy);
|
||||
extern void snap_keypoint_to_grid(struct mged_state *s);
|
||||
extern void snap_view_center_to_grid(struct mged_state *s);
|
||||
|
||||
@@ -146,7 +146,6 @@ set(
|
||||
helpcomm.tcl
|
||||
helplib.tcl
|
||||
hoc.tcl
|
||||
html_library.tcl
|
||||
libtclcad.tcl
|
||||
man_browser.tcl
|
||||
menu_override.tcl
|
||||
|
||||
@@ -6,7 +6,6 @@ chkexterns.tcl utility to check for the existence of commands
|
||||
fs_dialog.tk file selection dialog widget
|
||||
helpcomm.tcl generic help routines
|
||||
helplib.tcl library help routines
|
||||
html_library.tcl HTML display library by Stephen Uhler
|
||||
libdm.tcl libdm initialization routines
|
||||
mged directory of mged specific tcl scripts
|
||||
pl-dm directory of pl-dm specific tcl scripts
|
||||
|
||||
@@ -226,7 +226,7 @@ package provide Archer 1.0
|
||||
method buildViewAxesPreferences {}
|
||||
method doAboutArcher {}
|
||||
method doarcherHelp {}
|
||||
method handleMap {}
|
||||
method handleMap {_window}
|
||||
method handleBindingModeChange {_name1 _name2 _op}
|
||||
method overrideBindingMode {_mode}
|
||||
method updateOverrideBindingMode {_keysym}
|
||||
@@ -427,6 +427,7 @@ package provide Archer 1.0
|
||||
|
||||
private {
|
||||
variable mInstanceInit 1
|
||||
variable mWindowMapped 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,7 +529,7 @@ package provide Archer 1.0
|
||||
}
|
||||
|
||||
# resize and position window after it's drawn
|
||||
bind [namespace tail $this] <Map> [::itcl::code $this handleMap]
|
||||
bind [namespace tail $this] <Map> [::itcl::code $this handleMap %W]
|
||||
}
|
||||
|
||||
|
||||
@@ -4263,18 +4264,26 @@ proc title_node_handler {node} {
|
||||
|
||||
}
|
||||
|
||||
::itcl::body Archer::handleMap {} {
|
||||
if {$mWindowGeometry != ""} {
|
||||
after idle "wm geometry [namespace tail $this] $mWindowGeometry"
|
||||
} else {
|
||||
after idle "wm geometry [namespace tail $this] $itk_option(-geometry)"
|
||||
::itcl::body Archer::handleMap {_window} {
|
||||
# Child windows also dispatch Map events through the toplevel's tag.
|
||||
if {$_window ne [namespace tail $this]} {
|
||||
return
|
||||
}
|
||||
set mWindowMapped 1
|
||||
|
||||
set geometry $mWindowGeometry
|
||||
if {$geometry eq ""} {
|
||||
set geometry $itk_option(-geometry)
|
||||
}
|
||||
if {$geometry ne ""} {
|
||||
after idle [list wm geometry $_window $geometry]
|
||||
}
|
||||
|
||||
if {$mSeparateCommandWindow && $mCmdWindowGeometry != ""} {
|
||||
after idle [::itcl::code wm geometry $itk_component(sepcmdT) $mCmdWindowGeometry]
|
||||
after idle [list wm geometry $itk_component(sepcmdT) $mCmdWindowGeometry]
|
||||
}
|
||||
|
||||
bind [namespace tail $this] <Map> {}
|
||||
bind $_window <Map> {}
|
||||
}
|
||||
|
||||
::itcl::body Archer::handleDisplayEscape {_dm} {
|
||||
@@ -9351,7 +9360,17 @@ proc title_node_handler {node} {
|
||||
puts $_pfile "set mVPaneToggle3 $mVPaneToggle3"
|
||||
puts $_pfile "set mVPaneToggle5 $mVPaneToggle5"
|
||||
|
||||
puts $_pfile "set mWindowGeometry [winfo geometry [namespace tail $this]]"
|
||||
# Before the first map, the hull's size only reflects unfinished layout.
|
||||
if {$mWindowMapped} {
|
||||
if {$ArcherCore::inheritFromToplevel} {
|
||||
set mWindowGeometry [wm geometry [namespace tail $this]]
|
||||
} else {
|
||||
set mWindowGeometry [winfo geometry [namespace tail $this]]
|
||||
}
|
||||
}
|
||||
if {$mWindowGeometry ne ""} {
|
||||
puts $_pfile [list set mWindowGeometry $mWindowGeometry]
|
||||
}
|
||||
|
||||
if {$mSeparateCommandWindow} {
|
||||
puts $_pfile "set mCmdWindowGeometry [winfo geometry $itk_component(sepcmdT)]"
|
||||
|
||||
@@ -165,8 +165,7 @@ proc secErrorDialog {root title text default args} {
|
||||
update idletasks
|
||||
|
||||
# First frame consists of error icon and message
|
||||
frame $base.frame\#1 \
|
||||
-class Panedwindow
|
||||
frame $base.frame\#1
|
||||
pack $base.frame\#1 -fill x -anchor w
|
||||
|
||||
canvas $base.frame\#1.bitmap \
|
||||
|
||||
@@ -1,663 +0,0 @@
|
||||
# Simple HTML display library by Stephen Uhler (stephen.uhler@sun.com)
|
||||
# Copyright (c) 1995 by Sun Microsystems
|
||||
# Version 0.1 Thu Jul 20 09:06:28 PDT 1995
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
# To use this package, create a text widget (say, .text)
|
||||
# and set a variable full of html, (say $html), and issue:
|
||||
# HMinit_win .text
|
||||
# HMparse_html $html "HMrender .text"
|
||||
# You also need to supply the routine:
|
||||
# proc HMlink_callback {win href} { ...}
|
||||
# win: The name of the text widget
|
||||
# href The name of the link
|
||||
# which will be called anytime the user "clicks" on a link.
|
||||
# The supplied version just prints the link to stdout.
|
||||
# In addition, if you wish to use embedded images, you will need to write
|
||||
# proc HMset_image {handle src}
|
||||
# handle an arbitrary handle (not really)
|
||||
# src The name of the image
|
||||
# Which calls
|
||||
# HMgot_image $handle $image
|
||||
# with the TK image.
|
||||
#
|
||||
# To return a "used" text widget to its initialized state, call:
|
||||
# HMreset_win .text
|
||||
# See "sample.tcl" for sample usage
|
||||
##################################################################
|
||||
############################################
|
||||
# mapping of html tags to text tag properties
|
||||
# properties beginning with "T" map directly to text tags
|
||||
|
||||
# These are Defined in HTML 2.0
|
||||
|
||||
array set HMtag_map {
|
||||
a {Tlink link}
|
||||
b {weight bold}
|
||||
blockquote {style i indent 1 Trindent rindent}
|
||||
bq {style i indent 1 Trindent rindent}
|
||||
cite {style i}
|
||||
code {family courier}
|
||||
dfn {style i}
|
||||
dir {indent 1}
|
||||
dl {indent 1}
|
||||
em {style i}
|
||||
h1 {size 24 weight bold}
|
||||
h2 {size 22}
|
||||
h3 {size 20}
|
||||
h4 {size 18}
|
||||
h5 {size 16}
|
||||
h6 {style i}
|
||||
i {style i}
|
||||
kbd {family courier weight bold}
|
||||
menu {indent 1}
|
||||
ol {indent 1}
|
||||
pre {fill 0 family courier Tnowrap nowrap}
|
||||
samp {family courier}
|
||||
strong {weight bold}
|
||||
tt {family courier}
|
||||
u {Tunderline underline}
|
||||
ul {indent 1}
|
||||
var {style i}
|
||||
}
|
||||
|
||||
# These are in common(?) use, but not defined in html2.0
|
||||
|
||||
array set HMtag_map {
|
||||
center {Tcenter center}
|
||||
strike {Tstrike strike}
|
||||
u {Tunderline underline}
|
||||
}
|
||||
|
||||
# initial values
|
||||
|
||||
set HMtag_map(hmstart) {
|
||||
family times weight medium style r size 14
|
||||
Tcenter "" Tlink "" Tnowrap "" Tunderline "" list list
|
||||
fill 1 indent "" counter 0 adjust 0
|
||||
}
|
||||
|
||||
# html tags that insert white space
|
||||
|
||||
array set HMinsert_map {
|
||||
blockquote "\n\n" /blockquote "\n"
|
||||
br "\n"
|
||||
dd "\n" /dd "\n"
|
||||
dl "\n" /dl "\n"
|
||||
dt "\n"
|
||||
form "\n" /form "\n"
|
||||
h1 "\n\n" /h1 "\n"
|
||||
h2 "\n\n" /h2 "\n"
|
||||
h3 "\n\n" /h3 "\n"
|
||||
h4 "\n" /h4 "\n"
|
||||
h5 "\n" /h5 "\n"
|
||||
h6 "\n" /h6 "\n"
|
||||
li "\n"
|
||||
/dir "\n"
|
||||
/ul "\n"
|
||||
/ol "\n"
|
||||
/menu "\n"
|
||||
p "\n\n"
|
||||
pre "\n" /pre "\n"
|
||||
}
|
||||
|
||||
# tags that are list elements, that support "compact" rendering
|
||||
|
||||
array set HMlist_elements {
|
||||
ol 1 ul 1 menu 1 dl 1 dir 1
|
||||
}
|
||||
############################################
|
||||
# initialize the window and stack state
|
||||
|
||||
proc HMinit_win {win} {
|
||||
upvar #0 HM$win var
|
||||
|
||||
HMinit_state $win
|
||||
$win tag configure underline -underline 1
|
||||
$win tag configure center -justify center
|
||||
$win tag configure nowrap -wrap none
|
||||
$win tag configure rindent -rmargin $var(S_tab)c
|
||||
$win tag configure strike -overstrike 1
|
||||
$win tag configure mark -foreground red ;# list markers
|
||||
$win tag configure list -spacing1 3p -spacing3 3p ;# regular lists
|
||||
$win tag configure compact -spacing1 0p ;# compact lists
|
||||
$win tag configure link -foreground blue ;# hypertext links
|
||||
HMset_indent $win $var(S_tab)
|
||||
$win configure -wrap word
|
||||
|
||||
# for horizontal rules
|
||||
$win tag configure thin -font [HMx_font Times 14 Medium R]
|
||||
$win tag configure hr -relief sunken -borderwidth 2 -wrap none \
|
||||
-tabs [winfo width $win]
|
||||
bind $win <Configure> {%W tag configure hr -tabs %w}
|
||||
|
||||
# generic link enter callback
|
||||
|
||||
$win tag bind link <1> "HMlink_hit $win %x %y"
|
||||
}
|
||||
|
||||
# set the indent spacing (in cm) for lists
|
||||
# TK uses a "weird" tabbing model that causes \t to insert a single
|
||||
# space if the current line position is past the tab setting
|
||||
|
||||
proc HMset_indent {win cm} {
|
||||
set tabs [expr $cm / 2.0]
|
||||
$win configure -tabs ${tabs}c
|
||||
foreach i {1 2 3 4 5 6 7 8 9} {
|
||||
set tab [expr $i * $cm]
|
||||
$win tag configure indent$i -lmargin1 ${tab}c -lmargin2 ${tab}c \
|
||||
-tabs "[expr $tab + $tabs]c [expr $tab + 2*$tabs]c"
|
||||
}
|
||||
}
|
||||
|
||||
# reset the state of window - get ready for the next page
|
||||
# remove all but the font tags
|
||||
|
||||
proc HMreset_win {win} {
|
||||
regsub -all { +[^L ][^ ]*} " [$win tag names] " {} tags
|
||||
catch "$win tag delete $tags"
|
||||
eval $win mark unset [$win mark names]
|
||||
$win delete 0.0 end
|
||||
$win tag configure hr -tabs [winfo width $win]
|
||||
HMinit_state $win
|
||||
}
|
||||
|
||||
# initialize the window's state array
|
||||
# Parameters beginning with S_ are NOT reset
|
||||
# adjust_size: global font size adjuster
|
||||
# unknown: character to use for unknown entities
|
||||
# tab: tab stop (in cm)
|
||||
# stop: enabled to stop processing
|
||||
# update: how many tags between update calls
|
||||
# tags: number of tags processed so far
|
||||
# symbols: Symbols to use on un-ordered lists
|
||||
|
||||
proc HMinit_state {win} {
|
||||
upvar #0 HM$win var
|
||||
array set tmp [array get var S_*]
|
||||
catch {unset var}
|
||||
array set var {
|
||||
stop 0
|
||||
tags 0
|
||||
fill 0
|
||||
list list
|
||||
S_adjust_size 0
|
||||
S_tab 1.0
|
||||
S_unknown \xb7
|
||||
S_update 10
|
||||
S_symbols O*=+-o\xd7\xb0>:\xb7
|
||||
}
|
||||
array set var [array get tmp]
|
||||
}
|
||||
|
||||
# alter the parameters of the text state
|
||||
# this allows an application to over-ride the default settings
|
||||
# it is called as: HMset_state -param value -param value ...
|
||||
|
||||
array set HMparam_map {
|
||||
-update S_update
|
||||
-tabs S_tab
|
||||
-unknown S_unknown
|
||||
-stop S_stop
|
||||
-size S_adjust_size
|
||||
-symbols S_symbols
|
||||
}
|
||||
|
||||
proc HMset_state {win args} {
|
||||
upvar #0 HM$win var
|
||||
global HMparam_map
|
||||
set bad 0
|
||||
if {[catch {array set params $args}]} {return 0}
|
||||
foreach i [array names params] {
|
||||
incr bad [catch {set var($HMparam_map($i)) $params($i)}]
|
||||
}
|
||||
return [expr $bad == 0]
|
||||
}
|
||||
|
||||
############################################
|
||||
# manage the display of html
|
||||
|
||||
# this gets called for every html tag
|
||||
# win: The name of the text widget to render into
|
||||
# tag: The html tag (in arbitrary case)
|
||||
# not: a "/" or the empty string
|
||||
# param: The un-interpreted parameter list
|
||||
# text: The plain text until the next html tag
|
||||
|
||||
proc HMrender {win tag not param text} {
|
||||
upvar #0 HM$win var
|
||||
if {$var(stop)} return
|
||||
global HMtag_map HMinsert_map HMlist_elements
|
||||
set tag [string tolower $tag]
|
||||
set text [HMmap_esc $text]
|
||||
|
||||
# manage compact rendering of lists
|
||||
if {[info exists HMlist_elements($tag)]} {
|
||||
set list "list [expr {[HMextract_param $param compact] ? "compact" : "list"}]"
|
||||
} else {
|
||||
set list ""
|
||||
}
|
||||
|
||||
# adjust tag state
|
||||
catch {HMstack $win $not "$HMtag_map($tag) $list"}
|
||||
|
||||
# insert white space (with current font)
|
||||
# adding white space can get a bit tricky. This isn't quite right
|
||||
set bad [catch {$win insert end $HMinsert_map($not$tag) "space $var(font)"}]
|
||||
if {!$bad && [llength $var(fill)]>0 && [lindex $var(fill) end]} {
|
||||
set text [string trimleft $text]
|
||||
}
|
||||
|
||||
# to fill or not to fill
|
||||
if {[llength $var(fill)]>0 && [lindex $var(fill) end]} {
|
||||
set text [HMzap_white $text]
|
||||
}
|
||||
|
||||
# do any special tag processing
|
||||
catch {HMtag_$not$tag $win $param text} msg
|
||||
|
||||
# debugging only (code will not be here if no debugging was set)
|
||||
|
||||
# add the text with proper tags
|
||||
set tags [HMcurrent_tags $win]
|
||||
$win insert end $text $tags
|
||||
|
||||
# We need to do an update every so often to insure interactive response.
|
||||
# This can cause us to re-enter the event loop, and cause recursive
|
||||
# invocations of HMrender, so we need to be careful.
|
||||
if {!([incr var(tags)] % $var(S_update))} {
|
||||
update
|
||||
}
|
||||
}
|
||||
|
||||
# html tags requiring special processing
|
||||
# Procs of the form HMtag_<tag> or HMtag_</tag> get called just before
|
||||
# the text for this tag is displayed.
|
||||
# win: The name of the text widget to render into
|
||||
# param: The un-interpreted parameter list
|
||||
# text: A pass-by-reference name of the plain text until the next html tag
|
||||
# Tag commands may change this to affect what text will be inserted
|
||||
# next.
|
||||
|
||||
proc HMtag_title {win param text} {
|
||||
upvar $text data
|
||||
wm title [winfo toplevel $win] $data
|
||||
set data ""
|
||||
}
|
||||
|
||||
proc HMtag_hr {win param text} {
|
||||
$win insert end "\n" space "\n" thin "\t" "thin hr" "\n" thin
|
||||
}
|
||||
|
||||
# list element tags
|
||||
|
||||
proc HMtag_ol {win param text} {
|
||||
upvar #0 HM$win var
|
||||
set var(count$var(level)) 0
|
||||
}
|
||||
|
||||
proc HMtag_ul {win param text} {
|
||||
upvar #0 HM$win var
|
||||
catch {unset var(count$var(level))}
|
||||
}
|
||||
|
||||
proc HMtag_menu {win param text} {
|
||||
upvar #0 HM$win var
|
||||
set var(menu) ->
|
||||
set var(compact) 1
|
||||
}
|
||||
|
||||
proc HMtag_/menu {win param text} {
|
||||
upvar #0 HM$win var
|
||||
catch {unset var(menu)}
|
||||
catch {unset var(compact)}
|
||||
}
|
||||
|
||||
proc HMtag_dt {win param text} {
|
||||
upvar #0 HM$win var
|
||||
upvar $text data
|
||||
set level $var(level)
|
||||
incr level -1
|
||||
$win insert end "$data" "hi [lindex $var(list) end] indent$level $var(font)"
|
||||
set data {}
|
||||
}
|
||||
|
||||
proc HMtag_li {win param text} {
|
||||
upvar #0 HM$win var
|
||||
set level $var(level)
|
||||
incr level -1
|
||||
set x [string index $var(S_symbols)+-+-+-+-" $level]
|
||||
catch {set x [incr var(count$level)]}
|
||||
catch {set x $var(menu)}
|
||||
$win insert end \t$x\t "mark [lindex $var(list) end] indent$level $var(font)"
|
||||
}
|
||||
|
||||
# hypertext links.
|
||||
|
||||
proc HMtag_a {win param text} {
|
||||
upvar #0 HM$win var
|
||||
|
||||
if {[HMextract_param $param href]} {
|
||||
set var(Tref) L:$href
|
||||
HMlink_setup $win $href
|
||||
}
|
||||
}
|
||||
|
||||
proc HMtag_/a {win param text} {
|
||||
upvar #0 HM$win var
|
||||
catch {unset var(Tref)}
|
||||
}
|
||||
|
||||
# This interface is subject to change
|
||||
# Most of the work is getting around a limitation of TK that prevents
|
||||
# setting the size of a label to a widthxheight in pixels
|
||||
#
|
||||
# Images have the following parameters:
|
||||
# align: top,middle,bottom
|
||||
# alt: alternate text
|
||||
# ismap: A clickable image map
|
||||
# src: The URL link
|
||||
# Netscape supports
|
||||
# width: A width hint (in pixels)
|
||||
# height: A height hint (in pixels)
|
||||
# border: The size of the window border
|
||||
|
||||
proc HMtag_img {win param text} {
|
||||
upvar #0 HM$win var
|
||||
|
||||
# get alignment
|
||||
array set align_map {top top middle center bottom bottom}
|
||||
set align bottom ;# The spec isn't clear what the default should be
|
||||
HMextract_param $param align
|
||||
catch {set align $align_map([string tolower $align])}
|
||||
|
||||
# get alternate text
|
||||
set alt "<image>"
|
||||
HMextract_param $param alt
|
||||
set alt [HMmap_esc $alt]
|
||||
|
||||
# get the border width
|
||||
set border 1
|
||||
HMextract_param $param border
|
||||
|
||||
# see if we have an image size hint
|
||||
# If so, make a frame the "hint" size to put the label in
|
||||
# otherwise just make the label
|
||||
set item $win.$var(tags)
|
||||
catch {destroy $item}
|
||||
if {[HMextract_param $param width] && [HMextract_param $param height]} {
|
||||
frame $item -width $width -height $height
|
||||
pack propagate $item 0
|
||||
set label $item.label
|
||||
label $label
|
||||
pack $label -expand 1 -fill both
|
||||
} else {
|
||||
set label $item
|
||||
label $label
|
||||
}
|
||||
|
||||
$label configure -relief ridge -fg orange -text $alt
|
||||
catch {$label configure -bd $border}
|
||||
$win window create end -align $align -window $item -pady 2
|
||||
|
||||
# add in all the current tags (this is overkill)
|
||||
set tags [HMcurrent_tags $win]
|
||||
foreach tag $tags {
|
||||
$win tag add $tag $item
|
||||
}
|
||||
|
||||
# set imagemap callbacks
|
||||
if {[HMextract_param $param ismap]} {
|
||||
set link ""
|
||||
regsub -all {[^L]*L:([^ ]*).*} $tags {\1} link
|
||||
global HMevents
|
||||
foreach i [array names HMevents] {
|
||||
bind $label <$i> "%W configure $HMevents($i)"
|
||||
}
|
||||
bind ismap <ButtonRelease-1> "HMlink_callback $win $link?%x,%y"
|
||||
bindtags $label "ismap [bindtags $label]"
|
||||
}
|
||||
|
||||
# now callback to the application
|
||||
set src ""
|
||||
HMextract_param $param src
|
||||
HMset_image $label $src
|
||||
}
|
||||
|
||||
# The app needs to supply one of these
|
||||
#proc HMset_image {handle src} {
|
||||
# puts "Found an image <$src> to put in $handle"
|
||||
# HMgot_image $handle "can't get\n$src"
|
||||
#}
|
||||
|
||||
# When the image is available, the application should call back here.
|
||||
# If we have the image, put it in the label, otherwise display the error
|
||||
# message. If we don't get a callback, the "alt" text remains.
|
||||
# if we have a clickable image, arrange for a callback
|
||||
|
||||
proc HMgot_image {win image_error} {
|
||||
# if we're in a frame turn on geometry propagation
|
||||
if {[winfo name $win] == "label"} {
|
||||
pack propagate [winfo parent $win] 1
|
||||
}
|
||||
if {[catch {$win configure -image $image_error}]} {
|
||||
$win configure -image {}
|
||||
$win configure -text $image_error
|
||||
}
|
||||
}
|
||||
|
||||
# Sample hypertext link callback routine - should be replaced by app
|
||||
# This proc is called once for each <A> tag.
|
||||
# Applications can overwrite this procedure, as required, or
|
||||
# replace the HMevents array
|
||||
# win: The name of the text widget to render into
|
||||
# href: The HREF link for this <a> tag.
|
||||
|
||||
array set HMevents {
|
||||
Enter {-borderwidth 2 -relief raised }
|
||||
Leave {-borderwidth 0 -relief flat }
|
||||
1 {-borderwidth 2 -relief sunken}
|
||||
ButtonRelease-1 {-relief raised}
|
||||
}
|
||||
|
||||
proc HMlink_setup {win href} {
|
||||
global HMevents
|
||||
foreach i [array names HMevents] {
|
||||
eval $win tag bind L:$href <$i> \
|
||||
\{$win tag configure L:$href $HMevents($i)\}
|
||||
}
|
||||
}
|
||||
|
||||
# generic link-hit callback
|
||||
# This gets called upon button hits on hypertext links
|
||||
# Applications are expected to supply their own HMlink_callback routine
|
||||
# win: The name of the text widget to render into
|
||||
# x,y: The cursor position at the "click"
|
||||
|
||||
proc HMlink_hit {win x y} {
|
||||
set tags [$win tag names @$x,$y]
|
||||
regsub -all {[^L]*L:([^ ]*).*} $tags {\1} link
|
||||
HMlink_callback $win $link
|
||||
}
|
||||
|
||||
# replace this!
|
||||
# win: The name of the text widget to render into
|
||||
# href: The HREF link for this <a> tag.
|
||||
|
||||
#proc HMlink_callback {win href} {
|
||||
# puts "Got hit on $win, link $href"
|
||||
#}
|
||||
|
||||
# extract a value from parameter list (this needs a re-do)
|
||||
# returns "1" if the keyword is found, "0" otherwise
|
||||
# param: A parameter list. It should already have been processed to
|
||||
# remove any entity references
|
||||
# key: The parameter name
|
||||
# val: The variable to put the value into (use key as default)
|
||||
|
||||
proc HMextract_param {param key {val ""}} {
|
||||
|
||||
if {$val == ""} {
|
||||
upvar $key result
|
||||
} else {
|
||||
upvar $val result
|
||||
}
|
||||
|
||||
# look for name=value combinations. Either (') or (") are valid delimiters
|
||||
if {
|
||||
[regsub -nocase [format {.*%s *= *"([^"]*).*} $key] $param {\1} value] ||
|
||||
[regsub -nocase [format {.*%s *= *'([^']*).*} $key] $param {\1} value] ||
|
||||
[regsub -nocase [format {.*%s *= *([^ ]+).*} $key] $param {\1} value] } {
|
||||
set result $value
|
||||
return 1
|
||||
}
|
||||
|
||||
# now look for valueless names
|
||||
# I should strip out name=value pairs, so we don't end up with "name"
|
||||
# inside the "value" part of some other key word - some day
|
||||
|
||||
set bad \[^a-zA-Z\]+
|
||||
if {[regexp -nocase "$bad$key$bad" -$param-]} {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
# These next two routines manage the display state of the page.
|
||||
|
||||
# push or pop tags to/from stack
|
||||
# the current tag is the last item on the list
|
||||
|
||||
proc HMstack {win push list} {
|
||||
upvar #0 HM$win var
|
||||
array set tags $list
|
||||
if {$push == ""} {
|
||||
foreach tag [array names tags] {
|
||||
lappend var($tag) $tags($tag)
|
||||
}
|
||||
} else {
|
||||
foreach tag [array names tags] {
|
||||
set cnt [regsub { *[^ ]+$} $var($tag) {} var($tag)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# extract set of current text tags
|
||||
# tags starting with T map directly to text tags
|
||||
|
||||
proc HMcurrent_tags {win} {
|
||||
upvar #0 HM$win var
|
||||
set font font
|
||||
foreach i {family size weight style} {
|
||||
set $i [lindex $var($i) end]
|
||||
append font :[set $i]
|
||||
}
|
||||
set xfont [HMx_font $family $size $weight $style $var(S_adjust_size)]
|
||||
catch {$win tag configure $font -font $xfont} msg
|
||||
set indent [llength $var(indent)]
|
||||
incr indent -1
|
||||
lappend tags $font indent$indent
|
||||
foreach tag [array names var T*] {
|
||||
append tags " [lindex $var($tag) end]"
|
||||
}
|
||||
set var(font) $font
|
||||
set var(level) $indent
|
||||
return $tags
|
||||
}
|
||||
|
||||
# generate an X font name
|
||||
proc HMx_font {family size weight style {adjust_size 0}} {
|
||||
catch {incr size $adjust_size}
|
||||
return "-*-$family-$weight-$style-normal--${size}-*-*-*-*-*-*-*"
|
||||
}
|
||||
############################################
|
||||
# Turn HTML into TCL commands
|
||||
# html A string containing an html document
|
||||
# cmd A command to run for each html tag found
|
||||
|
||||
proc HMparse_html {html {cmd HMtest_parse}} {
|
||||
regsub -all \{ $html {\&ob;} html
|
||||
regsub -all \} $html {\&cb;} html
|
||||
set w " \t\r\n" ;# white space
|
||||
proc HMcl x {return "\[$x\]"}
|
||||
set exp <(/?)([HMcl ^$w>]+)[HMcl $w]*([HMcl ^>]*)>
|
||||
set sub "\}\n$cmd {\\2} {\\1} {\\3} \{"
|
||||
regsub -all $exp $html $sub html
|
||||
eval "$cmd hmstart {} {} \{ $html \}"
|
||||
eval "$cmd hmstart / {} {}"
|
||||
}
|
||||
|
||||
proc HMtest_parse {command tag slash text_after_tag} {
|
||||
puts "==> $command $tag $slash $text_after_tag"
|
||||
}
|
||||
|
||||
# Convert multiple white space into a single space
|
||||
|
||||
proc HMzap_white {data} {
|
||||
regsub -all "\[ \t\r\n\]+" $data " " data
|
||||
return $data
|
||||
}
|
||||
|
||||
# find HTML escape characters of the form &xxx;
|
||||
|
||||
proc HMmap_esc {text} {
|
||||
if {![regexp & $text]} {return $text}
|
||||
regsub -all {([][$\\])} $text {\\\1} new
|
||||
regsub -all {&#([0-9][0-9][0-9]?);?} \
|
||||
$new {[format %c \1]} new
|
||||
regsub -all {&([^ ;]+);?} $new {[HMdo_map \1]} new
|
||||
return [subst $new]
|
||||
}
|
||||
|
||||
# convert an HTML escape sequence into character
|
||||
|
||||
proc HMdo_map {text {unknown ?}} {
|
||||
global HMesc_map
|
||||
set result $unknown
|
||||
catch {set result $HMesc_map($text)}
|
||||
return $result
|
||||
}
|
||||
|
||||
# table of escape characters (ISO latin-1 esc's are in a different table)
|
||||
|
||||
array set HMesc_map {
|
||||
lt < gt > amp & quot \" copy \xa9
|
||||
reg \xae ob \x7b cb \x7d nbsp \xa0
|
||||
}
|
||||
#############################################################
|
||||
# ISO Latin-1 escape codes
|
||||
|
||||
array set HMesc_map {
|
||||
nbsp \xa0 iexcl \xa1 cent \xa2 pound \xa3 curren \xa4
|
||||
yen \xa5 brvbar \xa6 sect \xa7 uml \xa8 copy \xa9
|
||||
ordf \xaa laquo \xab not \xac shy \xad reg \xae
|
||||
hibar \xaf deg \xb0 plusmn \xb1 sup2 \xb2 sup3 \xb3
|
||||
acute \xb4 micro \xb5 para \xb6 middot \xb7 cedil \xb8
|
||||
sup1 \xb9 ordm \xba raquo \xbb frac14 \xbc frac12 \xbd
|
||||
frac34 \xbe iquest \xbf Agrave \xc0 Aacute \xc1 Acirc \xc2
|
||||
Atilde \xc3 Auml \xc4 Aring \xc5 AElig \xc6 Ccedil \xc7
|
||||
Egrave \xc8 Eacute \xc9 Ecirc \xca Euml \xcb Igrave \xcc
|
||||
Iacute \xcd Icirc \xce Iuml \xcf ETH \xd0 Ntilde \xd1
|
||||
Ograve \xd2 Oacute \xd3 Ocirc \xd4 Otilde \xd5 Ouml \xd6
|
||||
times \xd7 Oslash \xd8 Ugrave \xd9 Uacute \xda Ucirc \xdb
|
||||
Uuml \xdc Yacute \xdd THORN \xde szlig \xdf agrave \xe0
|
||||
aacute \xe1 acirc \xe2 atilde \xe3 auml \xe4 aring \xe5
|
||||
aelig \xe6 ccedil \xe7 egrave \xe8 eacute \xe9 ecirc \xea
|
||||
euml \xeb igrave \xec iacute \xed icirc \xee iuml \xef
|
||||
eth \xf0 ntilde \xf1 ograve \xf2 oacute \xf3 ocirc \xf4
|
||||
otilde \xf5 ouml \xf6 divide \xf7 oslash \xf8 ugrave \xf9
|
||||
uacute \xfa ucirc \xfb uuml \xfc yacute \xfd thorn \xfe
|
||||
yuml \xff
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# mode: Tcl
|
||||
# tab-width: 8
|
||||
# c-basic-offset: 4
|
||||
# tcl-indent-level: 4
|
||||
# indent-tabs-mode: t
|
||||
# End:
|
||||
# ex: shiftwidth=4 tabstop=8
|
||||
@@ -160,6 +160,13 @@ namespace eval hv3 {
|
||||
return $O(myWidget)
|
||||
}
|
||||
|
||||
# Namespace resolution can find an application-level search command
|
||||
# before invoking the unknown handler, so forward this method explicitly.
|
||||
proc search {me args} {
|
||||
upvar #0 $me O
|
||||
eval $O(myWidget) search $args
|
||||
}
|
||||
|
||||
proc unknown {method me args} {
|
||||
# puts "UNKNOWN: $me $method $args"
|
||||
upvar #0 $me O
|
||||
|
||||
@@ -63,6 +63,7 @@ if {[llength [info commands manpage_search_terms]] == 0} {
|
||||
}
|
||||
protected {
|
||||
method getPages {section}
|
||||
method loadSelectedPage {listbox}
|
||||
method refreshPageList {}
|
||||
method accordianCallback {_item _state}
|
||||
}
|
||||
@@ -126,6 +127,17 @@ if {[llength [info commands manpage_search_terms]] == 0} {
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# Load the page selected in the table of contents.
|
||||
#
|
||||
::itcl::body ManBrowser::loadSelectedPage {listbox} {
|
||||
set selection [$listbox curselection]
|
||||
if {[llength $selection] != 1} {
|
||||
return
|
||||
}
|
||||
loadPage [$listbox get $selection]
|
||||
}
|
||||
|
||||
##
|
||||
# Selects page in ToC & loads into HTML browser; used for command line calls
|
||||
#
|
||||
@@ -356,10 +368,8 @@ if {[llength [info commands manpage_search_terms]] == 0} {
|
||||
}
|
||||
|
||||
if {$itk_option(-useToC)} {
|
||||
bind $itk_component(manpagelistbox) <<ListboxSelect>> {
|
||||
set mb [itcl_info objects -class ManBrowser]
|
||||
$mb loadPage [%W get [%W curselection]]
|
||||
}
|
||||
bind $itk_component(manpagelistbox) <<ListboxSelect>> \
|
||||
[::itcl::code $this loadSelectedPage %W]
|
||||
}
|
||||
|
||||
# bind MouseWheel listener to the widget.document (this is the html
|
||||
|
||||
@@ -20,11 +20,21 @@
|
||||
###
|
||||
#
|
||||
# Description -
|
||||
# rouintes for displaying a Tcl/Tk widget for selecting a BOT face
|
||||
# routines for displaying a Tcl/Tk widget for selecting a BOT face
|
||||
#
|
||||
|
||||
proc bot_face_sel_apply { face } {
|
||||
if { [llength $face] != 3 } {
|
||||
return -code error "BOT face does not have 3 vertices"
|
||||
}
|
||||
|
||||
_mged_p {*}$face
|
||||
_mged_get_solid_keypoint
|
||||
_mged_refresh
|
||||
}
|
||||
|
||||
proc bot_face_select { face_list } {
|
||||
global bot_v1 bot_v2 bot_v3 mged_gui
|
||||
global mged_gui
|
||||
global ::tk::Priv
|
||||
|
||||
|
||||
@@ -46,71 +56,38 @@ proc bot_face_select { face_list } {
|
||||
|
||||
set face_list_len [llength $face_list]
|
||||
if { $face_list_len == 0 } {
|
||||
set bot_v1 -1
|
||||
set bot_v2 -1
|
||||
set bot_v3 -1
|
||||
bot_face_sel_abort $w
|
||||
return
|
||||
}
|
||||
|
||||
if { $face_list_len == 1 } {
|
||||
set face [lindex $face_list 0]
|
||||
if { [llength $face] != 3 } {
|
||||
set bot_v1 -1
|
||||
set bot_v2 -1
|
||||
set bot_v3 -1
|
||||
bot_face_sel_abort $w
|
||||
cad_dialog $::tk::Priv(cad_dialog) $screen "Internal Error" "Face does not have 3 vertices" error 0 OK
|
||||
return
|
||||
}
|
||||
set bot_v1 [lindex $face 0]
|
||||
set bot_v2 [lindex $face 1]
|
||||
set bot_v3 [lindex $face 2]
|
||||
get_solid_keypoint
|
||||
bot_face_sel_apply $face
|
||||
return
|
||||
}
|
||||
|
||||
create_listbox $w $screen "BOT Triangle" $face_list "bot_face_sel_abort $w"
|
||||
wm protocol $w WM_DELETE_WINDOW [list bot_face_sel_abort $w]
|
||||
bind_listbox $w "<B1-Motion>"\
|
||||
"set face \[get_listbox_entry %W %x %y\];\
|
||||
set bot_v1 \[lindex \$face 0\];\
|
||||
set bot_v2 \[lindex \$face 1\];\
|
||||
set bot_v3 \[lindex \$face 2\];\
|
||||
get_solid_keypoint;\
|
||||
refresh"
|
||||
if 0 {
|
||||
bind_listbox $w "<ButtonPress-1>"\
|
||||
"set face \[get_listbox_entry %W %x %y\];\
|
||||
set bot_v1 \[lindex \$face 0\];\
|
||||
set bot_v2 \[lindex \$face 1\];\
|
||||
set bot_v3 \[lindex \$face 2\];\
|
||||
get_solid_keypoint;\
|
||||
refresh"
|
||||
bind_listbox $w "<Double-1>"\
|
||||
"set face \[get_listbox_entry %W %x %y\];\
|
||||
set bot_v1 \[lindex \$face 0\];\
|
||||
set bot_v2 \[lindex \$face 1\];\
|
||||
set bot_v3 \[lindex \$face 2\];\
|
||||
get_solid_keypoint;\
|
||||
refresh;\
|
||||
destroy $w"
|
||||
} else {
|
||||
bind_listbox $w "<ButtonPress-1>" \
|
||||
"lbdcHack %W %x %y %t $id bf junkpath"
|
||||
}
|
||||
"bot_face_sel_apply \[get_listbox_entry %W %x %y\]"
|
||||
bind_listbox $w "<ButtonPress-1>" \
|
||||
"lbdcHack %W %x %y %t $id bf junkpath"
|
||||
hoc_register_data $w.listbox "BOT Triangle Select" {
|
||||
{summary "Use your left mouse button to highlight entries in this list.
|
||||
Each entry show the three vertex numbers that make up a single triangle.
|
||||
Each entry shows the three vertex numbers that make up a single triangle.
|
||||
Double click to select a triangle for editing."}
|
||||
}
|
||||
}
|
||||
|
||||
proc bot_face_sel_abort { w } {
|
||||
global bot_v1 bot_v2 bot_v3
|
||||
|
||||
set bot_v1 -1
|
||||
set bot_v2 -1
|
||||
set bot_v3 -1
|
||||
get_solid_keypoint
|
||||
catch "destroy $w"
|
||||
_mged_get_solid_keypoint
|
||||
_mged_refresh
|
||||
catch {destroy $w}
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
|
||||
@@ -74,7 +74,6 @@ proc lbdcHack {w x y t id type path} {
|
||||
global mged_gui
|
||||
global mged_default
|
||||
global comb_control
|
||||
global bot_v1 bot_v2 bot_v3
|
||||
|
||||
# set item from listbox selection @$x,$y
|
||||
switch $type {
|
||||
@@ -119,11 +118,7 @@ proc lbdcHack {w x y t id type path} {
|
||||
matrix_illum $path $item
|
||||
}
|
||||
bf {
|
||||
set bot_v1 [lindex $item 0];
|
||||
set bot_v2 [lindex $item 1];
|
||||
set bot_v3 [lindex $item 2];
|
||||
get_solid_keypoint;
|
||||
refresh;
|
||||
bot_face_sel_apply $item
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -158,11 +153,7 @@ proc lbdcHack {w x y t id type path} {
|
||||
set mged_gui($id,mgs_pos) $item
|
||||
}
|
||||
bf {
|
||||
set bot_v1 [lindex $item 0];
|
||||
set bot_v2 [lindex $item 1];
|
||||
set bot_v3 [lindex $item 2];
|
||||
get_solid_keypoint;
|
||||
refresh;
|
||||
bot_face_sel_apply $item
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+153
-124
@@ -43,15 +43,15 @@ if { [info exists tk_strictMotif] == 0 } {
|
||||
#------------------------------------------------------------------------------
|
||||
# vmath.tcl : The vector math library
|
||||
# menu.tcl : The Tk menu replacement
|
||||
# html_library.tcl : Stephen Uhler's routines for processing HTML
|
||||
#==============================================================================
|
||||
|
||||
# MGED html manual directory search order precedence should be:
|
||||
# MGED_HTML_DIR
|
||||
# [bu_dir data]/html/manuals/mged
|
||||
# [bu_dir doc]/html/manuals/mged
|
||||
|
||||
if ![info exists mged_default(html_dir)] {
|
||||
set mged_default(html_dir) [file normalize [file join [bu_dir doc] html manuals mged]]
|
||||
set mged_default(html_dir) [file normalize [file join [bu_dir data] html manuals mged]]
|
||||
if {![file exists $mged_default(html_dir)]} {
|
||||
set mged_default(html_dir) [file normalize [file join [bu_dir doc] html manuals mged]]
|
||||
}
|
||||
@@ -519,148 +519,177 @@ proc echo args {
|
||||
#==============================================================================
|
||||
# HTML support
|
||||
#==============================================================================
|
||||
proc man_goto { w screen } {
|
||||
global ia_url
|
||||
global ::tk::Priv
|
||||
namespace eval ::mged::manual {
|
||||
variable back_history
|
||||
variable suppress_history
|
||||
}
|
||||
|
||||
cad_input_dialog $::tk::Priv(cad_dialog) $screen "Go To" "Enter filename to read:" \
|
||||
filename $ia_url(current) \
|
||||
0 {{ summary "Enter a filename or URL."}} OK
|
||||
proc ::mged::manual::file_uri {path} {
|
||||
set uri_path [string map {\\ /} [file normalize $path]]
|
||||
if {[string index $uri_path 0] ne "/"} {
|
||||
set uri_path /$uri_path
|
||||
}
|
||||
set uri_path [::tkhtml::encode $uri_path]
|
||||
return file://[string map {%2F /} $uri_path]
|
||||
}
|
||||
|
||||
if { [file exists $filename]!=0 } {
|
||||
if { [string match /* $filename] } {
|
||||
set new_url $filename
|
||||
} else {
|
||||
set new_url [pwd]/$filename
|
||||
proc ::mged::manual::local_path {location} {
|
||||
set uri [::tkhtml::uri $location]
|
||||
set scheme [$uri scheme]
|
||||
set authority [$uri authority]
|
||||
set path [::tkhtml::decode [$uri path]]
|
||||
$uri destroy
|
||||
|
||||
if {![string equal -nocase $scheme file]} {
|
||||
error "unsupported URI scheme '$scheme'"
|
||||
}
|
||||
if {$authority ne "" && ![string equal -nocase $authority localhost]} {
|
||||
set path //$authority$path
|
||||
}
|
||||
if {$::tcl_platform(platform) eq "windows" &&
|
||||
[regexp {^/[A-Za-z]:/} $path]} {
|
||||
set path [string range $path 1 end]
|
||||
}
|
||||
return [file normalize $path]
|
||||
}
|
||||
|
||||
proc ::mged::manual::request_error {handle error_message} {
|
||||
global message
|
||||
|
||||
set message $error_message
|
||||
$handle configure -mimetype text/plain
|
||||
$handle finish $error_message
|
||||
}
|
||||
|
||||
proc ::mged::manual::request {handle} {
|
||||
global message
|
||||
|
||||
set location [$handle cget -uri]
|
||||
if {[catch {set path [local_path $location]} path_error]} {
|
||||
request_error $handle "Cannot read $location: $path_error"
|
||||
return
|
||||
}
|
||||
|
||||
set message "Reading file $path"
|
||||
if {[catch {
|
||||
set channel [open $path rb]
|
||||
try {
|
||||
set data [read $channel]
|
||||
} finally {
|
||||
close $channel
|
||||
}
|
||||
} read_error]} {
|
||||
request_error $handle "Cannot read $path: $read_error"
|
||||
return
|
||||
}
|
||||
$handle finish $data
|
||||
}
|
||||
|
||||
HMlink_callback $w.text $new_url
|
||||
} else {
|
||||
cad_dialog $::tk::Priv(cad_dialog) $screen "Error reading file" \
|
||||
"Cannot read file $filename." error 0 OK
|
||||
proc ::mged::manual::remember_location {viewer} {
|
||||
variable back_history
|
||||
variable suppress_history
|
||||
|
||||
if {[info exists suppress_history($viewer)] &&
|
||||
$suppress_history($viewer)} {
|
||||
return
|
||||
}
|
||||
if {[catch {$viewer location} location] ||
|
||||
$location eq "home://blank/"} {
|
||||
return
|
||||
}
|
||||
if {![info exists back_history($viewer)] ||
|
||||
[lindex $back_history($viewer) end] ne $location} {
|
||||
lappend back_history($viewer) $location
|
||||
}
|
||||
}
|
||||
|
||||
proc ia_man { parent screen } {
|
||||
global mged_html_dir ia_url message
|
||||
proc ::mged::manual::go_back {viewer} {
|
||||
variable back_history
|
||||
variable suppress_history
|
||||
|
||||
if {![info exists back_history($viewer)] ||
|
||||
![llength $back_history($viewer)]} {
|
||||
return
|
||||
}
|
||||
|
||||
set location [lindex $back_history($viewer) end]
|
||||
set back_history($viewer) [lrange $back_history($viewer) 0 end-1]
|
||||
set suppress_history($viewer) 1
|
||||
set status [catch {$viewer goto $location -nosave} result options]
|
||||
set suppress_history($viewer) 0
|
||||
if {$status} {
|
||||
return -options $options $result
|
||||
}
|
||||
}
|
||||
|
||||
proc ::mged::manual::go_to {viewer screen} {
|
||||
global ::tk::Priv
|
||||
|
||||
set initial_path [pwd]
|
||||
if {![catch {local_path [$viewer location]} current_path]} {
|
||||
set initial_path $current_path
|
||||
}
|
||||
cad_input_dialog $::tk::Priv(cad_dialog) $screen "Go To" \
|
||||
"Enter filename to read:" filename $initial_path \
|
||||
0 {{ summary "Enter the name of a local HTML file."}} OK
|
||||
|
||||
if {[file pathtype $filename] eq "relative"} {
|
||||
set filename [file join [pwd] $filename]
|
||||
}
|
||||
set filename [file normalize $filename]
|
||||
if {[file readable $filename] && ![file isdirectory $filename]} {
|
||||
$viewer goto [file_uri $filename]
|
||||
return
|
||||
}
|
||||
|
||||
cad_dialog $::tk::Priv(cad_dialog) $screen "Error reading file" \
|
||||
"Cannot read file $filename." error 0 OK
|
||||
}
|
||||
|
||||
proc ::mged::manual::cleanup {viewer destroyed_widget} {
|
||||
variable back_history
|
||||
variable suppress_history
|
||||
|
||||
if {$destroyed_widget ne $viewer} {
|
||||
return
|
||||
}
|
||||
unset -nocomplain back_history($viewer)
|
||||
unset -nocomplain suppress_history($viewer)
|
||||
}
|
||||
|
||||
proc ia_man {parent screen} {
|
||||
global mged_html_dir message
|
||||
|
||||
package require hv3
|
||||
|
||||
set w $parent.man
|
||||
catch { destroy $w }
|
||||
catch {destroy $w}
|
||||
toplevel $w -screen $screen
|
||||
wm title $w "MGED HTML browser"
|
||||
|
||||
frame $w.f -relief sunken -bd 1
|
||||
pack $w.f -side top -fill x
|
||||
|
||||
button $w.f.close -text Close -command "destroy $w"
|
||||
button $w.f.goto -text "Go To" -command "man_goto $w $screen"
|
||||
button $w.f.back -text "Back" -command "ia_man_back $w.text"
|
||||
set viewer [::hv3::hv3 $w.html \
|
||||
-requestcmd ::mged::manual::request]
|
||||
button $w.f.close -text Close -command [list destroy $w]
|
||||
button $w.f.goto -text "Go To" \
|
||||
-command [list ::mged::manual::go_to $viewer $screen]
|
||||
button $w.f.back -text "Back" \
|
||||
-command [list ::mged::manual::go_back $viewer]
|
||||
|
||||
pack $w.f.close $w.f.goto $w.f.back -side left -fill x -expand yes
|
||||
|
||||
label $w.message -textvar message -anchor w
|
||||
label $w.message -textvariable message -anchor w
|
||||
pack $w.message -side top -anchor w -fill x
|
||||
pack $viewer -side top -fill both -expand yes
|
||||
|
||||
scrollbar $w.scrolly -command "$w.text yview"
|
||||
scrollbar $w.scrollx -command "$w.text xview" -orient horizontal
|
||||
text $w.text -relief ridge -yscroll "$w.scrolly set" \
|
||||
-xscroll "$w.scrollx set"
|
||||
pack $w.scrolly -side right -fill y
|
||||
pack $w.text -side top -fill both -expand yes
|
||||
pack $w.scrollx -side bottom -fill x
|
||||
set ::mged::manual::back_history($viewer) {}
|
||||
set ::mged::manual::suppress_history($viewer) 0
|
||||
bind $viewer <<Goto>> +[list ::mged::manual::remember_location $viewer]
|
||||
bind $viewer <Destroy> +[list ::mged::manual::cleanup $viewer %W]
|
||||
|
||||
set w $w.text
|
||||
|
||||
HMinit_win $w
|
||||
set ia_url(current) $mged_html_dir/
|
||||
set ia_url(last) ""
|
||||
set ia_url(backtrack) ""
|
||||
HMlink_callback $w contents.html
|
||||
}
|
||||
|
||||
proc HMlink_callback { w href } {
|
||||
global ia_url message
|
||||
|
||||
if {[string match /* $href]} {
|
||||
set new_url $href
|
||||
} else {
|
||||
if { [file isdirectory $ia_url(current)] } {
|
||||
set new_url $ia_url(current)$href
|
||||
} else {
|
||||
set new_url [file dirname $ia_url(current)]/$href
|
||||
}
|
||||
}
|
||||
|
||||
# Remove tags
|
||||
regsub {"#[0-9a-zA-Z]*"} $new_url {} ia_url(current)
|
||||
lappend ia_url(last) $ia_url(current)
|
||||
set ia_url(backtrack) [lrange $ia_url(last) 0 \
|
||||
[expr [llength $ia_url(last)]-2]]
|
||||
|
||||
HMreset_win $w
|
||||
HMparse_html [ia_get_html $ia_url(current)] "HMrender $w"
|
||||
update
|
||||
}
|
||||
|
||||
proc ia_man_back { w } {
|
||||
global ia_url message
|
||||
|
||||
if {[llength $ia_url(backtrack)]<1} {
|
||||
return
|
||||
}
|
||||
|
||||
set new_url [lindex $ia_url(backtrack) end]
|
||||
set ia_url(backtrack) [lrange $ia_url(backtrack) 0 \
|
||||
[expr [llength $ia_url(backtrack)]-2]]
|
||||
|
||||
HMreset_win $w
|
||||
HMparse_html [ia_get_html $new_url] "HMrender $w"
|
||||
update
|
||||
}
|
||||
|
||||
proc HMset_image { handle src } {
|
||||
global ia_url message
|
||||
|
||||
if {[string match http://* $src]} {
|
||||
return
|
||||
}
|
||||
|
||||
if {[string match /* $src]} {
|
||||
set image $src
|
||||
} else {
|
||||
set image [file dirname $ia_url(current)]/$src
|
||||
}
|
||||
|
||||
set message "Fetching image $image."
|
||||
update
|
||||
if {[string first " $image " " [image names] "] >= 0} {
|
||||
HMgot_image $handle $image
|
||||
} else {
|
||||
catch {image create photo $image -file $image} image
|
||||
HMgot_image $handle $image
|
||||
}
|
||||
}
|
||||
|
||||
proc ia_get_html {file} {
|
||||
global message ia_url
|
||||
|
||||
set message "Reading file $file"
|
||||
update
|
||||
|
||||
if {[string match *.gif $file]} {
|
||||
return "<img src=\"[file tail $file]\">"
|
||||
}
|
||||
|
||||
if {[catch {set fd [open $file]} msg]} {
|
||||
return "
|
||||
<title>Bad file $file</title>
|
||||
<h1>Error reading $file</h1><p>
|
||||
$msg<hr>
|
||||
"
|
||||
}
|
||||
set result [read $fd]
|
||||
close $fd
|
||||
return $result
|
||||
set contents [file join $mged_html_dir contents.html]
|
||||
$viewer goto [::mged::manual::file_uri $contents]
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
|
||||
Reference in New Issue
Block a user