Compare commits
30
Commits
editchecks
...
displayfix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acd957aec3 | ||
|
|
f7a8d5b406 | ||
|
|
85de3929e5 | ||
|
|
0a8c6d8bc2 | ||
|
|
a00efd15c6 | ||
|
|
06c8ab6204 | ||
|
|
cd55562c46 | ||
|
|
6d142b62e7 | ||
|
|
da2f503367 | ||
|
|
a9ac66788a | ||
|
|
4cc9f9cf01 | ||
|
|
7b1898d9fd | ||
|
|
e4d297893e | ||
|
|
0173dd8c40 | ||
|
|
cf344d773e | ||
|
|
8c51c1d527 | ||
|
|
6e48ea9ddd | ||
|
|
488f538040 | ||
|
|
17cc9f3a5a | ||
|
|
bf2c508826 | ||
|
|
f2e68b1a2a | ||
|
|
5e873e5081 | ||
|
|
3beed70eb8 | ||
|
|
73258d4264 | ||
|
|
8ae7482918 | ||
|
|
917ce5554c | ||
|
|
58ab0d5496 | ||
|
|
13b0699349 | ||
|
|
acd3a9800d | ||
|
|
03b36c1b61 |
+1
-1
@@ -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(12115e6c5922e2db27a9b88e00dd714af5315f69)
|
||||
brlcad_bext_init(0682795bcfe34644c17e5a4bdd0225c76f6bdc98)
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Define various utilities.
|
||||
|
||||
@@ -61,6 +61,8 @@ changes made. See document footer for additional details.
|
||||
* 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
|
||||
* improved fallback methodologies for facetize pipeline - Cliff Yapp
|
||||
* improved facetize pipeline robustness - Cliff Yapp
|
||||
* added arrange nest command for packing database objects - Sean Morrison
|
||||
* new mkbuilding tool for parametric/OSM/CityJSON models - Sean Morrison
|
||||
* cross-platform BINUNIF and DSP byte-order handling - Sean Morrison
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
BRL-CAD
|
||||
Release 7.44.2
|
||||
http://brlcad.org/
|
||||
BRL-CAD
|
||||
Release 7.44.2
|
||||
http://brlcad.org/
|
||||
|
||||
BRL-CAD is a powerful cross-platform open source combinatorial
|
||||
solid modeling system that includes an interactive 3D solid geometry
|
||||
|
||||
@@ -200,17 +200,55 @@ ____
|
||||
|
||||
The LIBRT_DEBUG environment variable may be set to the hexadecimal bit vector as described by the DEBUG_* flags listed in the raytrace.h header. Similarly, many LIBRT applications provide a "-x #" command-line option which will take precedence over the environment variable.
|
||||
|
||||
The RT_DEBUG_RTCMP flag (0x10000000) (set with LIBRT_DEBUG=10000000) appends
|
||||
one high-precision rtcmp JSON record per ray with final hit partitions to the
|
||||
file named by LIBRT_RTCMP_FILE. Misses produce no record. librt never clears
|
||||
the file; the caller must clear or rotate it before a new comparison as needed.
|
||||
Separate processes must not write to the same file concurrently. Pending
|
||||
records are flushed within two seconds under normal operation and during normal
|
||||
process shutdown. A process terminated abnormally may lose pending records.
|
||||
rtcmp comparison files should use the same hit-only capture mode on both sides;
|
||||
its generation mode also includes misses. The output can be expanded to also
|
||||
include primitive segments if the environment variable LIBRT_RTCMP_PRIMITIVES
|
||||
is set to 1.
|
||||
The RT_DEBUG_RTCMP flag (0x10000000) (set with LIBRT_DEBUG=10000000)
|
||||
sets up rtcmp capture, but recording starts disabled. Set
|
||||
LIBRT_RTCMP_FILE before enabling the flag, then call
|
||||
rt_rtcmp_capture_set_enabled(1) from the application or a debugger to
|
||||
record selected rays. Call rt_rtcmp_capture_set_enabled(0) to stop
|
||||
recording. Enabling returns -1 if the debug flag is unset or the output
|
||||
writer failed to initialize; disabling returns 0 even before setup. A
|
||||
ray must begin while recording is enabled, and leaving recording
|
||||
disabled when it finishes suppresses its record. The debug flag must be
|
||||
set before concurrent ray shooting; use the setter to change recording
|
||||
state while rays are running.
|
||||
|
||||
Captured hits append one high-precision rtcmp JSON record per ray with
|
||||
final partitions. Misses produce no record. librt never clears the
|
||||
output file; the caller must clear or rotate it before a new comparison
|
||||
as needed. Separate processes must not write to the same file
|
||||
concurrently. Pending records are flushed within two seconds under
|
||||
normal operation and during normal process shutdown; call
|
||||
rt_rtcmp_capture_flush() to wait for pending records when using a
|
||||
debugger. Disabling recording does not discard records already queued. A
|
||||
process terminated abnormally may lose pending records. rtcmp comparison
|
||||
files should use the same hit-only capture mode on both sides; its
|
||||
generation mode also includes misses. The output can be expanded to also
|
||||
include primitive segments if LIBRT_RTCMP_PRIMITIVES is set to 1 before
|
||||
capture is set up.
|
||||
|
||||
For example, run a single-threaded ray tracing application in a debugger
|
||||
and stop at `rt_shootray` for the suspect ray. Capture just that call,
|
||||
then compare it with a capture of the same ray from a reference build:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
$ LIBRT_DEBUG=10000000 LIBRT_RTCMP_FILE=trial.json \
|
||||
gdb --args ./ray_application model.g
|
||||
(gdb) break rt_shootray
|
||||
(gdb) run
|
||||
(gdb) call rt_rtcmp_capture_set_enabled(1)
|
||||
(gdb) finish
|
||||
(gdb) call rt_rtcmp_capture_set_enabled(0)
|
||||
(gdb) call rt_rtcmp_capture_flush()
|
||||
(gdb) quit
|
||||
$ rtcmp -c reference.json trial.json
|
||||
----
|
||||
|
||||
Continue to the suspect ray before enabling capture if the breakpoint
|
||||
first stops on another ray. Produce `reference.json` with the same ray
|
||||
and the same capture mode; set LIBRT_RTCMP_PRIMITIVES=1 for both runs
|
||||
when primitive segments are needed to locate a difference before Boolean
|
||||
evaluation.
|
||||
|
||||
The LIBRT_V4FLIP environment variable may be set to a true or false value to respectively force or disable endianness interpretation of v4 geometry database files. The default behavior is to automatically detect whether flipping the endian interpretation will help LIBRT read a binary-incompatible v4 geometry database file. Setting LIBRT_V4FLIP will override automatic detection.
|
||||
|
||||
|
||||
@@ -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
@@ -84,7 +84,7 @@ __BEGIN_DECLS
|
||||
#define RT_DEBUG_HF 0x04000000 /**< @brief 27 Height Field solids */
|
||||
|
||||
#define RT_DEBUG_MESHING 0x08000000 /**< @brief 28 Print meshing/triangulation details */
|
||||
#define RT_DEBUG_RTCMP 0x10000000 /**< @brief 29 Append rays to LIBRT_RTCMP_FILE; LIBRT_RTCMP_PRIMITIVES=1 includes primitive segments */
|
||||
#define RT_DEBUG_RTCMP 0x10000000 /**< @brief 29 Set up rtcmp capture; recording uses a runtime toggle. If LIBRT_RTCMP_PRIMITIVES=1 includes primitive segments. */
|
||||
#define RT_DEBUG_UNUSED_4 0x20000000 /**< @brief 30 Unassigned */
|
||||
|
||||
/* Options which will cause the library to write binary debugging output */
|
||||
|
||||
+6
-4
@@ -510,7 +510,9 @@ rt_knob_edit_sca(
|
||||
int matrix_edit);
|
||||
|
||||
/* Equivalent to sedit - run editing logic after input data is set in
|
||||
* rt_edit container. Returns BRLCAD_ERROR if the primitive edit fails. */
|
||||
* rt_edit container. Transient input flags are consumed whether the edit
|
||||
* succeeds or fails; parameter values remain available to the caller.
|
||||
* Returns BRLCAD_ERROR if the primitive edit fails. */
|
||||
RT_EXPORT extern int
|
||||
rt_edit_process(struct rt_edit *s);
|
||||
|
||||
@@ -532,7 +534,7 @@ rt_edit_snap_point(point2d_t pt, const struct rt_edit *s);
|
||||
* restored later with rt_edit_revert().
|
||||
*
|
||||
* The snapshot is stored inside the rt_edit struct. Calling this
|
||||
* function again overwrites any previous snapshot (single-level undo).
|
||||
* function again replaces the previous snapshot only on success.
|
||||
*
|
||||
* @return BRLCAD_OK on success, BRLCAD_ERROR if the export failed.
|
||||
*/
|
||||
@@ -543,8 +545,8 @@ rt_edit_checkpoint(struct rt_edit *s);
|
||||
* Restore primitive parameters from the snapshot saved by
|
||||
* rt_edit_checkpoint().
|
||||
*
|
||||
* If no snapshot has been saved (or the last snapshot was already
|
||||
* consumed) this function logs a message and returns BRLCAD_ERROR.
|
||||
* The snapshot remains available for repeated restores. If none has
|
||||
* been saved, this function logs a message and returns BRLCAD_ERROR.
|
||||
*
|
||||
* @return BRLCAD_OK on success, BRLCAD_ERROR otherwise.
|
||||
*/
|
||||
|
||||
@@ -55,6 +55,15 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define RT_RTCMP_CAPTURE_RUNTIME_TOGGLE 1
|
||||
|
||||
/** Set RT_DEBUG_RTCMP recording: nonzero enables, zero disables.
|
||||
* Enabling requires the debug flag and a usable output writer.
|
||||
* Return 0 on success and -1 on failure. Disabling succeeds even
|
||||
* before setup.
|
||||
*/
|
||||
RT_EXPORT extern int rt_rtcmp_capture_set_enabled(int enabled);
|
||||
|
||||
/** Wait until pending RT_DEBUG_RTCMP records have reached the output file. */
|
||||
RT_EXPORT extern int rt_rtcmp_capture_flush(void);
|
||||
|
||||
|
||||
@@ -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 ***"
|
||||
|
||||
@@ -962,8 +962,140 @@ foreach test [list \
|
||||
csg_matrix_mouse_check {*}$test
|
||||
}
|
||||
|
||||
puts "--- Repeated graphical object transforms ---"
|
||||
proc csg_matrix_repeated_mouse_check {} {
|
||||
global orig_gui transform csg_mouse_dm_pixels csg_mouse_view_size
|
||||
global csg_drag_scale
|
||||
set prim csg_matrix_repeat.s
|
||||
set inner csg_matrix_repeat_inner.c
|
||||
set outer csg_matrix_repeat_outer.c
|
||||
set saved_orig_gui $orig_gui
|
||||
set expected [csg_edit_identity_matrix]
|
||||
set failed [catch {
|
||||
in $prim sph 0 0 0 10
|
||||
comb $inner u $prim
|
||||
comb $outer u $inner
|
||||
set orig_gui 0
|
||||
for {set step 0} {$step < 16} {incr step} {
|
||||
e $outer
|
||||
center 0 0 0
|
||||
size $csg_mouse_view_size
|
||||
setview 0 0 0
|
||||
dm size $csg_mouse_dm_pixels $csg_mouse_dm_pixels
|
||||
_mged_press oill
|
||||
_mged_ill -e -i 1 /$outer/$inner/$prim
|
||||
_mged_matpick 2
|
||||
if {[status state] ne "OBJ EDIT" || $transform ne "e"} {
|
||||
error "step $step did not enter object editing"
|
||||
}
|
||||
set view_before [csg_edit_view_state]
|
||||
if {$step % 2 == 0} {
|
||||
press Rotate
|
||||
dm con r z 100 100
|
||||
set operation [csg_matrix_axis_rotation z 10]
|
||||
set motion {dm motion 140 100}
|
||||
} else {
|
||||
press Scale
|
||||
dm am s 100 100
|
||||
set operation [csg_matrix_scale all $csg_drag_scale]
|
||||
set motion {dm motion 164 100}
|
||||
}
|
||||
set motion_code [catch {uplevel #0 $motion} motion_result]
|
||||
if {$motion_code != 0 && $motion_code != 2} {
|
||||
error "step $step mouse motion failed: $motion_result"
|
||||
}
|
||||
dm idle
|
||||
press accept
|
||||
set expected [csg_matrix_multiply $operation $expected]
|
||||
csg_edit_comb_leaf_matrix_at $inner $prim $expected
|
||||
csg_edit_view_state_at $view_before
|
||||
d $outer
|
||||
}
|
||||
} failure]
|
||||
set orig_gui $saved_orig_gui
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
foreach object [list $outer $inner $prim] {
|
||||
catch {kill $object}
|
||||
}
|
||||
if {$failed} {
|
||||
puts " FAIL: repeated object mouse rotations/scales ($failure)"
|
||||
} else {
|
||||
puts " PASS: repeated object mouse rotations/scales"
|
||||
}
|
||||
}
|
||||
csg_matrix_repeated_mouse_check
|
||||
|
||||
puts "--- All ARB point, edge, and face states ---"
|
||||
|
||||
proc csg_edit_sed_point {attribute} {
|
||||
set serialized [get_sed]
|
||||
set index [lsearch -exact $serialized $attribute]
|
||||
if {$index < 0 || $index + 1 >= [llength $serialized]} {
|
||||
error "get_sed has no $attribute: $serialized"
|
||||
}
|
||||
return [lindex $serialized [expr {$index + 1}]]
|
||||
}
|
||||
|
||||
proc csg_arb_repeated_mouse_check {} {
|
||||
global orig_gui csg_bv_coord_half_range csg_mouse_dm_pixels
|
||||
global csg_mouse_view_size
|
||||
set source csg_lifecycle_arb5.s
|
||||
set prim csg_arb_repeat.s
|
||||
set saved_orig_gui $orig_gui
|
||||
set expected {}
|
||||
set failed [catch {
|
||||
cp $source $prim
|
||||
e $prim
|
||||
center 0 0 0
|
||||
size $csg_mouse_view_size
|
||||
setview 0 0 0
|
||||
dm size $csg_mouse_dm_pixels $csg_mouse_dm_pixels
|
||||
set orig_gui 0
|
||||
sed $prim
|
||||
press {Move Edges}
|
||||
press {Move Point 5}
|
||||
set original_z [lindex [db get $source V5] 2]
|
||||
for {set step 0} {$step < 64} {incr step} {
|
||||
if {$step > 0 && $step % 8 == 0} {
|
||||
press sedit
|
||||
press {Move Edges}
|
||||
press {Move Point 5}
|
||||
}
|
||||
set mouse_x [expr {150 + 2 * ($step % 5)}]
|
||||
set mouse_y [expr {150 + 2 * (($step * 3) % 5)}]
|
||||
M 1 $mouse_x $mouse_y
|
||||
set expected [list \
|
||||
[expr {$mouse_x / $csg_bv_coord_half_range * $csg_mouse_view_size / 2.0}] \
|
||||
[expr {$mouse_y / $csg_bv_coord_half_range * $csg_mouse_view_size / 2.0}] \
|
||||
$original_z]
|
||||
set actual [csg_edit_sed_point V5]
|
||||
if {[csg_edit_point_distance $actual $expected] > 0.000001} {
|
||||
error "step $step expected V5 $expected, got $actual"
|
||||
}
|
||||
}
|
||||
press accept
|
||||
d $prim
|
||||
if {[csg_edit_point_distance [db get $prim V5] $expected] > 0.000001} {
|
||||
error "accepted V5 differs from the final mouse target"
|
||||
}
|
||||
foreach vertex {V1 V2 V3 V4} {
|
||||
csg_edit_point_matches_source $source $vertex $prim
|
||||
}
|
||||
arb_standard_storage_check arb5 $prim
|
||||
} failure]
|
||||
set orig_gui $saved_orig_gui
|
||||
catch {press reject}
|
||||
catch {d $prim}
|
||||
catch {kill $prim}
|
||||
if {$failed} {
|
||||
puts " FAIL: repeated ARB5 mouse movement ($failure)"
|
||||
} else {
|
||||
puts " PASS: repeated ARB5 mouse movement"
|
||||
}
|
||||
}
|
||||
csg_arb_repeated_mouse_check
|
||||
|
||||
# Every ARB menu entry is checked independently. The variants do not share
|
||||
# menu indices, so sampling one edge or face would miss precisely the class of
|
||||
# integration failure this test is intended to catch. Move each selection a
|
||||
@@ -1322,6 +1454,280 @@ csg_edit_sequence_check csg_lifecycle_dsp.s "Toggle Smooth" {
|
||||
{press {Toggle Smooth}}
|
||||
} [list csg_edit_scalar_at sm 1]
|
||||
|
||||
puts "--- Specialized mouse editing and menu inventory ---"
|
||||
proc csg_edit_prepare_mouse_view {} {
|
||||
global csg_dispatch_view_size
|
||||
center 0 0 0
|
||||
size $csg_dispatch_view_size
|
||||
setview 0 0 0
|
||||
}
|
||||
array set csg_mouse_covered {}
|
||||
proc csg_mouse_case {source menu_items label commands validator} {
|
||||
global csg_mouse_covered
|
||||
csg_edit_sequence_check $source $label $commands $validator
|
||||
set type [lindex [db get $source] 0]
|
||||
if {![info exists csg_mouse_covered($type)]} {
|
||||
set csg_mouse_covered($type) {}
|
||||
}
|
||||
foreach item $menu_items {
|
||||
if {[lsearch -exact $csg_mouse_covered($type) $item] < 0} {
|
||||
lappend csg_mouse_covered($type) $item
|
||||
}
|
||||
}
|
||||
}
|
||||
proc csg_edit_menu_inventory_check {source ignored} {
|
||||
global csg_mouse_covered
|
||||
if {[catch {
|
||||
Z
|
||||
e $source
|
||||
sed $source
|
||||
set actual [mmenu_get 0]
|
||||
set type [lindex [db get $source] 0]
|
||||
set covered {}
|
||||
if {[info exists csg_mouse_covered($type)]} {
|
||||
set covered $csg_mouse_covered($type)
|
||||
}
|
||||
foreach item $actual {
|
||||
set tested [expr {[lsearch -exact $covered $item] >= 0}]
|
||||
set exempt [expr {[lsearch -exact $ignored $item] >= 0}]
|
||||
if {$tested == $exempt} {
|
||||
error "menu entry '$item' needs exactly one mouse-test or exclusion"
|
||||
}
|
||||
}
|
||||
foreach item [concat $covered $ignored] {
|
||||
if {[lsearch -exact $actual $item] < 0} {
|
||||
error "recorded menu entry '$item' is absent from $actual"
|
||||
}
|
||||
}
|
||||
press reject
|
||||
d $source
|
||||
} failure]} {
|
||||
puts " FAIL: menu inventory $source ($failure)"
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
} else {
|
||||
puts " PASS: menu inventory $source"
|
||||
}
|
||||
}
|
||||
|
||||
csg_edit_prepare_mouse_view
|
||||
set csg_special_mouse_target [list \
|
||||
[expr {512.0 / $csg_bv_coord_half_range * $csg_dispatch_view_size / 2.0}] \
|
||||
[expr {512.0 / $csg_bv_coord_half_range * $csg_dispatch_view_size / 2.0}] 0]
|
||||
set csg_special_mouse_scale [expr {1.0 + 2047.0 / ($csg_bv_coord_half_range * 4.0)}]
|
||||
set csg_special_mouse_shrink [expr {
|
||||
1.0 / (1.0 + 1024.0 / ($csg_bv_coord_half_range * 4.0))}]
|
||||
csg_mouse_case csg_lifecycle_pipe.s {{Move Point}} "mouse select and move point" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Select Point}}
|
||||
{p 0 0 0}
|
||||
{press {Move Point}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V0 $csg_special_mouse_target]
|
||||
in csg_mouse_pipe_topology.s pipe 4 \
|
||||
0 0 0 1 2 3 \
|
||||
0 0 30 1 2 3 \
|
||||
30 40 80 1 2 3 \
|
||||
80 80 100 1 2 3
|
||||
csg_mouse_case csg_mouse_pipe_topology.s {{Select Point} {Move Point}} "mouse select point" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Select Point}}
|
||||
{M 1 0 0}
|
||||
{press {Move Point}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V0 $csg_special_mouse_target]
|
||||
csg_mouse_case csg_mouse_pipe_topology.s {{Append Point}} "mouse append point" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Append Point}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V4 {5 5 0}]
|
||||
csg_mouse_case csg_mouse_pipe_topology.s {{Prepend Point}} "mouse prepend point" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Prepend Point}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V0 {5 5 0}]
|
||||
csg_mouse_case csg_mouse_pipe_topology.s {{Split Segment}} "mouse split segment" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Select Point}}
|
||||
{p 0 0 0}
|
||||
{press {Split Segment}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_point_at V1 {5 5 0}]
|
||||
foreach {item attribute initial} {
|
||||
{Set Point OD} O0 5
|
||||
{Set Point ID} I0 3
|
||||
{Set Point Bend} R0 6
|
||||
} {
|
||||
csg_mouse_case csg_lifecycle_pipe.s [list $item] "mouse $item" [list \
|
||||
{csg_edit_prepare_mouse_view} \
|
||||
{press {Select Point}} {p 0 0 0} [list press $item] \
|
||||
{M 1 0 -1024}] \
|
||||
[list csg_edit_scalar_at $attribute [expr {$initial * $csg_special_mouse_shrink}]]
|
||||
}
|
||||
foreach {item attributes initial} {
|
||||
{Set Pipe OD} {O0 O1 O2 O3} {5 5 6 6}
|
||||
{Set Pipe ID} {I0 I1 I2 I3} {3 3 2 0}
|
||||
{Set Pipe Bend} {R0 R1 R2 R3} {6 7 10 8}
|
||||
} {
|
||||
set expected {}
|
||||
foreach value $initial {
|
||||
lappend expected [expr {$value * $csg_special_mouse_shrink}]
|
||||
}
|
||||
csg_mouse_case csg_lifecycle_pipe.s [list $item] "mouse $item" [list \
|
||||
{csg_edit_prepare_mouse_view} \
|
||||
[list press $item] {M 1 0 -1024}] \
|
||||
[list csg_edit_scalar_values_at $attributes $expected]
|
||||
}
|
||||
proc csg_edit_bot_vertices_moved {source moved delta prim} {
|
||||
set vertices [db get $source V]
|
||||
for {set index 0} {$index < [llength $vertices]} {incr index} {
|
||||
set expected [lindex $vertices $index]
|
||||
if {[lsearch -exact $moved $index] >= 0} {
|
||||
set translated {}
|
||||
foreach value $expected shift $delta {
|
||||
lappend translated [expr {$value + $shift}]
|
||||
}
|
||||
set expected $translated
|
||||
}
|
||||
csg_edit_list_value_at V $index $expected $prim
|
||||
}
|
||||
}
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Move Vertex}} "mouse move vertex" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Vertex}}
|
||||
{p 0}
|
||||
{press {Move Vertex}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0} \
|
||||
$csg_special_mouse_target]
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Pick Vertex} {Move Vertex}} "mouse pick and move vertex" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Vertex}}
|
||||
{M 1 0 0}
|
||||
{press {Move Vertex}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0} \
|
||||
$csg_special_mouse_target]
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Move Edge}} "mouse move edge" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Edge}}
|
||||
{p 0 1}
|
||||
{press {Move Edge}}
|
||||
{M 1 1024 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0 1} {10 5 0}]
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Pick Edge} {Move Edge}} "mouse pick and move edge" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Edge}}
|
||||
{M 1 512 512}
|
||||
{press {Move Edge}}
|
||||
{M 1 1024 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0 1} {10 5 0}]
|
||||
csg_mouse_case csg_lifecycle_bot.s {{Move Triangle}} "mouse move triangle" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Pick Triangle}}
|
||||
{p 0 1 2}
|
||||
{press {Move Triangle}}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_bot_vertices_moved csg_lifecycle_bot.s {0 1 2} \
|
||||
$csg_special_mouse_target]
|
||||
csg_mouse_case csg_lifecycle_ebm.s {{Extrude Depth}} "mouse extrusion depth" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Extrude Depth}}
|
||||
{M 1 0 2047}
|
||||
} [list csg_edit_scalar_at H [expr {4.0 * $csg_special_mouse_scale}]]
|
||||
csg_mouse_case csg_lifecycle_vol.s {{Threshold (low)}} "mouse low threshold" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Threshold (low)}}
|
||||
{p 10}
|
||||
{M 1 0 2047}
|
||||
} [list csg_edit_scalar_at lo [expr {int(10.0 * $csg_special_mouse_scale)}]]
|
||||
csg_mouse_case csg_lifecycle_vol.s {{Voxel Size (X Y Z)}} "mouse voxel size" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Voxel Size (X Y Z)}}
|
||||
{M 1 0 2047}
|
||||
} [list csg_edit_point_at size [list \
|
||||
$csg_special_mouse_scale $csg_special_mouse_scale $csg_special_mouse_scale]]
|
||||
csg_mouse_case csg_lifecycle_vol.s {{Threshold (hi)}} "mouse high threshold" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Threshold (hi)}}
|
||||
{M 1 0 -1024}
|
||||
} [list csg_edit_scalar_at hi [expr {int(255.0 * $csg_special_mouse_shrink)}]]
|
||||
csg_mouse_case csg_lifecycle_dsp.s {{Set X}} "mouse X scale" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{press {Set X}}
|
||||
{M 1 0 2047}
|
||||
} [list csg_edit_matrix_component_at stom 0 $csg_special_mouse_scale]
|
||||
foreach {item index} {{Set Y} 5 {Set ALT} 10} {
|
||||
csg_mouse_case csg_lifecycle_dsp.s [list $item] "mouse $item" [list \
|
||||
{csg_edit_prepare_mouse_view} \
|
||||
[list press $item] {M 1 0 2047}] \
|
||||
[list csg_edit_matrix_component_at stom $index $csg_special_mouse_scale]
|
||||
}
|
||||
foreach type {arbn brep} {
|
||||
set source csg_lifecycle_${type}.s
|
||||
csg_edit_sequence_check $source "generic mouse translation" {
|
||||
{csg_edit_prepare_mouse_view}
|
||||
{keypoint 0 0 0}
|
||||
{press sxy}
|
||||
{M 1 512 512}
|
||||
} [list csg_edit_bbox_translated $source $csg_special_mouse_target]
|
||||
}
|
||||
|
||||
# Every specialized menu entry must be accounted for. Exclusions are menu
|
||||
# headings, non-positional actions/settings, or the BOT triangle picker (tested
|
||||
# under Xmin because it needs Tk). A new entry without a mouse case or
|
||||
# explicit exclusion fails here.
|
||||
foreach {source ignored} {
|
||||
csg_lifecycle_pipe.s {
|
||||
{PIPE MENU} {Next Point} {Previous Point} {Delete Point}
|
||||
}
|
||||
csg_lifecycle_bot.s {
|
||||
{BOT MENU} {Pick Triangle} {Move Vertex List}
|
||||
{Split Edge} {Split Face} {Fuse Vertices} {Fuse Faces}
|
||||
{Delete Triangle} {Select Mode} {Select Orientation}
|
||||
{Set flags} {Set Face Thickness} {Set Face Mode}
|
||||
}
|
||||
csg_lifecycle_dsp.s {
|
||||
{DSP MENU} Name {Toggle Smooth} {Set Data Source}
|
||||
}
|
||||
csg_lifecycle_ebm.s {
|
||||
{EBM MENU} {File Name} {File Size (W N)}
|
||||
}
|
||||
csg_lifecycle_vol.s {
|
||||
{VOL MENU} {File Name} {File Size (X Y Z)}
|
||||
}
|
||||
csg_lifecycle_arbn.s {}
|
||||
csg_lifecycle_brep.s {}
|
||||
} {
|
||||
csg_edit_menu_inventory_check $source $ignored
|
||||
}
|
||||
|
||||
# A view-space request must remain view-space even when the editor's current
|
||||
# coordinate system is object-relative. This is the fast path underlying the
|
||||
# corresponding real mouse drag in the Xmin GUI test.
|
||||
set csg_saved_coords [rset var coords]
|
||||
set csg_saved_transform [rset var transform]
|
||||
if {[catch {
|
||||
Z
|
||||
e csg_lifecycle_bot.s
|
||||
sed csg_lifecycle_bot.s
|
||||
center 0 0 0
|
||||
rset var coords o
|
||||
rset var transform v
|
||||
knob -i -v aX 1
|
||||
if {[csg_edit_point_distance [center] {-1 0 0}] > 0.000001} {
|
||||
error "explicit view knob left center at [center]"
|
||||
}
|
||||
} csg_view_override_error]} {
|
||||
puts " FAIL: view-space translation with object coordinates ($csg_view_override_error)"
|
||||
} else {
|
||||
puts " PASS: view-space translation with object coordinates"
|
||||
}
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
rset var coords $csg_saved_coords
|
||||
rset var transform $csg_saved_transform
|
||||
|
||||
file delete -force $csg_data_file
|
||||
file delete -force $csg_dsp_file
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ in tor_pe.s tor 0 0 0 0 0 1 20 2
|
||||
prim_edit_check tor_pe.s "Set Radius 1" 30 r_a 30 -1
|
||||
prim_edit_check tor_pe.s "Set Radius 2" 5 r_h 5 -1
|
||||
prim_edit_mouse_check tor_pe.s "Set Radius 1" r_a 30 -1
|
||||
prim_edit_mouse_check tor_pe.s "Set Radius 2" r_h 5 -1
|
||||
kill tor_pe.s
|
||||
|
||||
puts "--- ELL (ellipsoid: A, B, C) ---"
|
||||
@@ -39,6 +40,8 @@ prim_edit_check ell_pe.s "Set A" 8 A 8 0
|
||||
prim_edit_check ell_pe.s "Set B" 6 B 6 1
|
||||
prim_edit_check ell_pe.s "Set C" 4 C 4 2
|
||||
prim_edit_mouse_check ell_pe.s "Set A" A 8 0
|
||||
prim_edit_mouse_check ell_pe.s "Set B" B 6 1
|
||||
prim_edit_mouse_check ell_pe.s "Set C" C 4 2
|
||||
kill ell_pe.s
|
||||
|
||||
puts "--- RPC (right parabolic cylinder: H, r) ---"
|
||||
@@ -46,6 +49,7 @@ in rpc_pe.s rpc 0 0 0 0 0 10 0 5 0 3
|
||||
prim_edit_check rpc_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check rpc_pe.s "Set r" 6 r 6 -1
|
||||
prim_edit_mouse_check rpc_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check rpc_pe.s "Set r" r 6 -1
|
||||
kill rpc_pe.s
|
||||
|
||||
puts "--- RHC (right hyperbolic cylinder: H, r, c) ---"
|
||||
@@ -54,6 +58,8 @@ prim_edit_check rhc_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check rhc_pe.s "Set r" 6 r 6 -1
|
||||
prim_edit_check rhc_pe.s "Set c" 3 c 3 -1
|
||||
prim_edit_mouse_check rhc_pe.s "Set r" r 6 -1
|
||||
prim_edit_mouse_check rhc_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check rhc_pe.s "Set c" c 3 -1
|
||||
kill rhc_pe.s
|
||||
|
||||
puts "--- EPA (elliptical paraboloid: H, r_1, r_2) ---"
|
||||
@@ -62,6 +68,8 @@ prim_edit_check epa_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check epa_pe.s "Set A" 8 r_1 8 -1
|
||||
prim_edit_check epa_pe.s "Set B" 4 r_2 4 -1
|
||||
prim_edit_mouse_check epa_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check epa_pe.s "Set A" r_1 8 -1
|
||||
prim_edit_mouse_check epa_pe.s "Set B" r_2 4 -1
|
||||
kill epa_pe.s
|
||||
|
||||
puts "--- EHY (elliptical hyperboloid: H, r_1, c) ---"
|
||||
@@ -70,6 +78,8 @@ prim_edit_check ehy_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check ehy_pe.s "Set A" 8 r_1 8 -1
|
||||
prim_edit_check ehy_pe.s "Set c" 3 c 3 -1
|
||||
prim_edit_mouse_check ehy_pe.s "Set A" r_1 8 -1
|
||||
prim_edit_mouse_check ehy_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check ehy_pe.s "Set c" c 3 -1
|
||||
kill ehy_pe.s
|
||||
|
||||
puts "--- PART (particle: H, r_v, r_h) ---"
|
||||
@@ -78,6 +88,8 @@ prim_edit_check part_pe.s "Set H" 20 H 20 2
|
||||
prim_edit_check part_pe.s "Set v" 4 r_v 4 -1
|
||||
prim_edit_check part_pe.s "Set h" 3 r_h 3 -1
|
||||
prim_edit_mouse_check part_pe.s "Set v" r_v 4 -1
|
||||
prim_edit_mouse_check part_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check part_pe.s "Set h" r_h 3 -1
|
||||
kill part_pe.s
|
||||
|
||||
puts "--- TGC (truncated general cone: H, A, B, C, D) ---"
|
||||
@@ -91,6 +103,10 @@ prim_edit_check tgc_pe.s "Set B" 3 B 3 1
|
||||
prim_edit_check tgc_pe.s "Set C" 3 C 3 0
|
||||
prim_edit_check tgc_pe.s "Set D" 4 D 4 1
|
||||
prim_edit_mouse_check tgc_pe.s "Set H" H 8 2
|
||||
prim_edit_mouse_check tgc_pe.s "Set A" A 4 0
|
||||
prim_edit_mouse_check tgc_pe.s "Set B" B 3 1
|
||||
prim_edit_mouse_check tgc_pe.s "Set C" C 3 0
|
||||
prim_edit_mouse_check tgc_pe.s "Set D" D 4 1
|
||||
kill tgc_pe.s
|
||||
|
||||
puts "--- ETO (elliptical torus: r, C, D) ---"
|
||||
@@ -100,6 +116,7 @@ prim_edit_check eto_pe.s "Set r" 8 r 8 -1
|
||||
prim_edit_check eto_pe.s "Set D" 1.5 r_d 1.5 -1
|
||||
prim_edit_mouse_check eto_pe.s "Set r" r 8 -1
|
||||
prim_edit_mouse_check eto_pe.s "Set C" C 5 0
|
||||
prim_edit_mouse_check eto_pe.s "Set D" r_d 1.5 -1
|
||||
kill eto_pe.s
|
||||
|
||||
puts "--- HYP (one-sheet hyperboloid: H, A, B, c) ---"
|
||||
@@ -111,6 +128,9 @@ prim_edit_check hyp_pe.s "Set A" 2 A 10 1
|
||||
prim_edit_check hyp_pe.s "Set B" 2 b 4 -1
|
||||
prim_edit_check hyp_pe.s "Set c" 0.5 bnr 0.25 -1
|
||||
prim_edit_mouse_check hyp_pe.s "Set H" H 20 2
|
||||
prim_edit_mouse_check hyp_pe.s "Set A" A 10 1
|
||||
prim_edit_mouse_check hyp_pe.s "Set B" b 4 -1
|
||||
prim_edit_mouse_check hyp_pe.s "Set c" bnr 0.25 -1
|
||||
kill hyp_pe.s
|
||||
|
||||
puts "--- SUPERELL (superellipsoid: A, B, C) ---"
|
||||
@@ -119,6 +139,8 @@ prim_edit_check superell_pe.s "Set A" 5 A 5 0
|
||||
prim_edit_check superell_pe.s "Set B" 4 B 4 1
|
||||
prim_edit_check superell_pe.s "Set C" 3 C 3 2
|
||||
prim_edit_mouse_check superell_pe.s "Set A" A 5 0
|
||||
prim_edit_mouse_check superell_pe.s "Set B" B 4 1
|
||||
prim_edit_mouse_check superell_pe.s "Set C" C 3 2
|
||||
kill superell_pe.s
|
||||
|
||||
puts "--- CLINE (cylinder line: H, R, plate thickness) ---"
|
||||
@@ -129,6 +151,7 @@ prim_edit_check cline_pe.s "Set R" 4 R 4 -1
|
||||
prim_edit_check cline_pe.s "Set plate thickness" 0.4 T 0.4 -1
|
||||
prim_edit_mouse_check cline_pe.s "Set H" H 8 2
|
||||
prim_edit_mouse_check cline_pe.s "Set R" R 4 -1
|
||||
prim_edit_mouse_check cline_pe.s "Set plate thickness" T 0.4 -1
|
||||
kill cline_pe.s
|
||||
|
||||
puts "--- NMG (non-manifold geometry: Pick Edge, Move Edge, Next EU) ---"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
puts "*** Testing 'sed_reset' command ***"
|
||||
|
||||
proc sed_reset_check {primitive edit_commands} {
|
||||
e $primitive
|
||||
sed $primitive
|
||||
if {[status state] ne "SOL EDIT"} {
|
||||
error "$primitive entered [status state], not SOL EDIT"
|
||||
}
|
||||
|
||||
set original [get_sed]
|
||||
foreach command $edit_commands {
|
||||
uplevel #0 $command
|
||||
}
|
||||
if {[get_sed] eq $original} {
|
||||
error "$primitive edit did not change the working geometry"
|
||||
}
|
||||
|
||||
sed_reset
|
||||
if {[status state] ne "SOL EDIT"} {
|
||||
error "$primitive reset entered [status state], not SOL EDIT"
|
||||
}
|
||||
if {[get_sed] ne $original} {
|
||||
error "$primitive reset did not restore the original geometry"
|
||||
}
|
||||
|
||||
press reject
|
||||
if {[status state] ne "VIEWING"} {
|
||||
error "$primitive reject entered [status state], not VIEWING"
|
||||
}
|
||||
d $primitive
|
||||
}
|
||||
|
||||
if {[catch {
|
||||
in sed_reset_arb8.s arb8 \
|
||||
0 0 0 10 0 0 10 10 0 0 10 0 \
|
||||
0 0 10 10 0 10 10 10 10 0 10 10
|
||||
sed_reset_check sed_reset_arb8.s {
|
||||
{press {Move Faces}}
|
||||
{press {Move Face 1234}}
|
||||
{p 0 0 -1}
|
||||
}
|
||||
} failure]} {
|
||||
puts "FAIL: ARB8 face move reset ($failure)"
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
} else {
|
||||
puts "PASS: ARB8 face move reset"
|
||||
}
|
||||
|
||||
if {[catch {
|
||||
make sed_reset_cline.s cline
|
||||
sed_reset_check sed_reset_cline.s {
|
||||
{press {Move End H}}
|
||||
{p 3 4 12}
|
||||
}
|
||||
} failure]} {
|
||||
puts "FAIL: CLINE edit reset ($failure)"
|
||||
catch {press reject}
|
||||
catch {Z}
|
||||
} else {
|
||||
puts "PASS: CLINE edit reset"
|
||||
}
|
||||
|
||||
puts "PASS: 'sed_reset' testing completed"
|
||||
@@ -93,6 +93,7 @@ if(BRLCAD_X11_PROVIDER_RESOLVED STREQUAL "XMIN" AND
|
||||
"PLOT3_ASC_BIN=$<TARGET_FILE:plot3-asc>"
|
||||
)
|
||||
mged_add_xmin_gui_fixture(help "mged;dm-tkswrast;m35.g")
|
||||
mged_add_xmin_gui_fixture(edit-interaction "mged;dm-tkswrast;m35.g")
|
||||
mged_add_xmin_gui_fixture(bot "mged;dm-tkswrast;m35.g")
|
||||
mged_add_xmin_gui_fixture(editors "mged;dm-tkswrast;m35.g")
|
||||
mged_add_xmin_gui_fixture(query-pattern "mged;dm-tkswrast;m35.g")
|
||||
@@ -212,18 +213,19 @@ cmakefiles(
|
||||
mged/mged_xmin_gui.sh
|
||||
mged/xmin_gui_bot.tcl
|
||||
mged/xmin_gui_controls.tcl
|
||||
mged/xmin_gui_edit.tcl
|
||||
mged/xmin_gui_edit_interaction.tcl
|
||||
mged/xmin_gui_editors.tcl
|
||||
mged/xmin_gui_help.tcl
|
||||
mged/xmin_gui_lod.tcl
|
||||
mged/xmin_gui_overlaps.tcl
|
||||
mged/xmin_gui_pipe_oracle.tcl
|
||||
mged/xmin_gui_query_pattern.tcl
|
||||
mged/xmin_gui_render_outputs.tcl
|
||||
mged/xmin_gui_search_exec.tcl
|
||||
mged/xmin_gui_shotvis.tcl
|
||||
mged/xmin_gui_test.tcl
|
||||
mged/xmin_gui_workflows.tcl
|
||||
mged/xmin_gui_edit.tcl
|
||||
mged/xmin_gui_pipe_oracle.tcl
|
||||
)
|
||||
|
||||
# Local Variables:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
|
||||
@@ -254,15 +254,9 @@ qtgl_open(void *ctx, void *UNUSED(interp), int argc, const char **argv)
|
||||
if (bu_vls_strlen(&dmp->i->dm_pathName) == 0)
|
||||
bu_vls_printf(&dmp->i->dm_pathName, ".dm_qtgl%d", count);
|
||||
++count;
|
||||
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
|
||||
char *dp;
|
||||
|
||||
dp = getenv("DISPLAY");
|
||||
if (dp)
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, dp);
|
||||
else
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, ":0.0");
|
||||
}
|
||||
/* The supplied QOpenGLWidget determines the Qt display. Keep dm_dName
|
||||
* empty unless the caller supplied -d; DISPLAY is an X11 setting and
|
||||
* cannot identify a Qt context on every supported platform. */
|
||||
|
||||
/* initialize dm specific variables */
|
||||
pubvars->devmotionnotify = 0;
|
||||
|
||||
@@ -246,15 +246,9 @@ swrast_open(void *ctx, void *UNUSED(interp), int argc, const char **argv)
|
||||
if (bu_vls_strlen(&dmp->i->dm_pathName) == 0)
|
||||
bu_vls_printf(&dmp->i->dm_pathName, ".dm_swrast%d", count);
|
||||
++count;
|
||||
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
|
||||
char *dp;
|
||||
|
||||
dp = getenv("DISPLAY");
|
||||
if (dp)
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, dp);
|
||||
else
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, ":0.0");
|
||||
}
|
||||
/* OSMesa is offscreen and has no display to discover. Leave dm_dName
|
||||
* empty unless the caller supplied -d; a window-system wrapper can then
|
||||
* select its own initialized display without inheriting X11 state. */
|
||||
|
||||
/* initialize dm specific variables */
|
||||
pubvars->devmotionnotify = 0;
|
||||
|
||||
@@ -464,6 +464,16 @@ tkswrast_open(void *ctx, void *vinterp, int argc, const char **argv)
|
||||
tv->orig_configureWin = dmp->i->dm_configureWin;
|
||||
tv->orig_close = dmp->i->dm_close;
|
||||
|
||||
/* The wrapped offscreen backend deliberately has no default display.
|
||||
* For this Tk presentation layer, use the display Tk actually opened.
|
||||
* This remains correct for X11, Win32, and Aqua even when the process
|
||||
* inherited an unrelated DISPLAY value. An explicit -d remains intact
|
||||
* and is validated below by Tk_CreateWindowFromPath. */
|
||||
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
|
||||
bu_vls_printf(&dmp->i->dm_dName, "%s.%d", Tk_DisplayName(tkwin),
|
||||
Tk_ScreenNumber(tkwin));
|
||||
}
|
||||
|
||||
char *cp = strrchr(bu_vls_addr(&dmp->i->dm_pathName), '.');
|
||||
if (dmp->i->dm_top) {
|
||||
tv->xtkwin = Tk_CreateWindowFromPath(interp, tkwin,
|
||||
|
||||
+13
-8
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1033,13 +1040,11 @@ wgl_open(void *UNUSED(ctx), void *vinterp, int argc, const char *argv[])
|
||||
++count;
|
||||
|
||||
if (bu_vls_strlen(&dmp->i->dm_dName) == 0) {
|
||||
char *dp;
|
||||
|
||||
dp = getenv("DISPLAY");
|
||||
if (dp)
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, dp);
|
||||
else
|
||||
bu_vls_strcpy(&dmp->i->dm_dName, ":0.0");
|
||||
/* DISPLAY names an X server and is not meaningful to WGL. Unix-like
|
||||
* shells on Windows may nevertheless export it, so use the screen of
|
||||
* the Tk window that supplies the native HWND. */
|
||||
bu_vls_printf(&dmp->i->dm_dName, "%s.%d", Tk_DisplayName(tkwin),
|
||||
Tk_ScreenNumber(tkwin));
|
||||
}
|
||||
|
||||
/* initialize dm specific variables */
|
||||
|
||||
+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;
|
||||
|
||||
+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;
|
||||
|
||||
+61
-23
@@ -1107,6 +1107,14 @@ rt_knob_edit_sca(struct rt_edit *s, int matrix_edit)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rt_edit_clear_input(struct rt_edit *s)
|
||||
{
|
||||
s->e_inpara = 0;
|
||||
s->e_mvalid = 0;
|
||||
s->es_scale = 0.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A great deal of magic takes place here, to accomplish solid editing.
|
||||
*
|
||||
@@ -1122,7 +1130,20 @@ rt_edit_process(struct rt_edit *s)
|
||||
bu_clbk_t f = NULL;
|
||||
void *d = NULL;
|
||||
|
||||
++s->update_views;
|
||||
if (!s)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
const int type = s->es_int.idb_type;
|
||||
if (type <= ID_NULL || type > ID_MAX_SOLID ||
|
||||
!s->es_int.idb_ptr || EDOBJ[type].magic != RT_FUNCTAB_MAGIC) {
|
||||
bu_vls_printf(s->log_str, "rt_edit_process: no editable solid\n");
|
||||
rt_edit_clear_input(s);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
const int prior_update_views = s->update_views;
|
||||
if (!s->update_views)
|
||||
s->update_views = 1;
|
||||
|
||||
int had_method = 0;
|
||||
const struct rt_db_internal *ip = &s->es_int;
|
||||
@@ -1134,6 +1155,8 @@ rt_edit_process(struct rt_edit *s)
|
||||
if (f)
|
||||
(*f)(0, NULL, d, NULL);
|
||||
}
|
||||
s->update_views = prior_update_views;
|
||||
rt_edit_clear_input(s);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
if (bu_vls_strlen(s->log_str)) {
|
||||
@@ -1149,7 +1172,7 @@ rt_edit_process(struct rt_edit *s)
|
||||
|
||||
case RT_EDIT_IDLE:
|
||||
/* do nothing more */
|
||||
--s->update_views;
|
||||
s->update_views = prior_update_views;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
@@ -1166,6 +1189,8 @@ rt_edit_process(struct rt_edit *s)
|
||||
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
|
||||
if (f)
|
||||
(*f)(0, NULL, d, NULL);
|
||||
s->update_views = prior_update_views;
|
||||
rt_edit_clear_input(s);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -1196,9 +1221,7 @@ rt_edit_process(struct rt_edit *s)
|
||||
}
|
||||
|
||||
// Inputs processed, reset
|
||||
s->e_inpara = 0;
|
||||
s->e_mvalid = 0;
|
||||
s->es_scale = 0.0;
|
||||
rt_edit_clear_input(s);
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
@@ -1221,15 +1244,15 @@ rt_edit_checkpoint(struct rt_edit *s)
|
||||
|
||||
RT_CK_DB_INTERNAL(&s->es_int);
|
||||
|
||||
/* Release any previous snapshot */
|
||||
bu_free_external(&s->es_ckpt);
|
||||
BU_EXTERNAL_INIT(&s->es_ckpt);
|
||||
|
||||
if (rt_obj_export(&s->es_ckpt, &s->es_int, 1.0, s->dbip) < 0) {
|
||||
struct bu_external candidate = BU_EXTERNAL_INIT_ZERO;
|
||||
if (rt_obj_export(&candidate, &s->es_int, 1.0, s->dbip) < 0) {
|
||||
bu_free_external(&candidate);
|
||||
bu_vls_printf(s->log_str, "rt_edit_checkpoint: export failed\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
bu_free_external(&s->es_ckpt);
|
||||
s->es_ckpt = candidate;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
@@ -1245,26 +1268,41 @@ rt_edit_revert(struct rt_edit *s)
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
int type = s->es_int.idb_type;
|
||||
|
||||
/* Release current contents */
|
||||
rt_db_free_internal(&s->es_int);
|
||||
RT_DB_INTERNAL_INIT(&s->es_int);
|
||||
|
||||
/* rt_obj_import dispatches on ip->idb_minor_type, which RT_DB_INTERNAL_INIT
|
||||
* resets to -1. Restore the saved type so the right ft_importN is called. */
|
||||
s->es_int.idb_minor_type = type;
|
||||
const int type = s->es_int.idb_type;
|
||||
if (type <= ID_NULL || type > ID_MAX_SOLID || !s->es_int.idb_ptr) {
|
||||
bu_vls_printf(s->log_str, "rt_edit_revert: no editable solid\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
struct rt_db_internal restored;
|
||||
RT_DB_INTERNAL_INIT(&restored);
|
||||
restored.idb_minor_type = type;
|
||||
mat_t identity;
|
||||
MAT_IDN(identity);
|
||||
if (rt_obj_import(&s->es_int, &s->es_ckpt, identity, s->dbip) < 0) {
|
||||
int import_result = rt_obj_import(&restored, &s->es_ckpt, identity, s->dbip);
|
||||
/* SPH and REC import through the ELL and TGC internal formats. */
|
||||
bool compatible_type = restored.idb_type == type ||
|
||||
(type == ID_SPH && restored.idb_type == ID_ELL) ||
|
||||
(type == ID_REC && restored.idb_type == ID_TGC);
|
||||
if (import_result < 0 || !compatible_type || !restored.idb_ptr) {
|
||||
rt_db_free_internal(&restored);
|
||||
bu_vls_printf(s->log_str, "rt_edit_revert: import failed\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
/* If the type changed for some reason (shouldn't happen), keep the original */
|
||||
if (s->es_int.idb_type != type)
|
||||
s->es_int.idb_type = type;
|
||||
restored.idb_type = type;
|
||||
restored.idb_meth = &OBJ[type];
|
||||
|
||||
if (s->ipe_ptr && EDOBJ[type].ft_prim_edit_reset)
|
||||
(*EDOBJ[type].ft_prim_edit_reset)(s);
|
||||
rt_db_free_internal(&s->es_int);
|
||||
s->es_int = restored;
|
||||
rt_edit_clear_input(s);
|
||||
s->acc_sc_sol = 1.0;
|
||||
if (!s->e_keyfixed) {
|
||||
s->e_keytag = "";
|
||||
rt_get_solid_keypoint(s, &s->e_keypoint, &s->e_keytag, s->e_mat);
|
||||
}
|
||||
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@ extern void flip_dbmat_mat(dbfloat_t *dbp, const fastf_t *ff);
|
||||
*/
|
||||
extern fastf_t ell_angle(fastf_t *p1, fastf_t a, fastf_t b, fastf_t dtol, fastf_t ntol);
|
||||
|
||||
int _rt_rtcmp_capture_ready(void);
|
||||
/* Append an rtcmp record for a ray with final partitions. */
|
||||
void _rt_rtcmp_capture(const struct application *ap, const struct partition *parts);
|
||||
/* Optional per-ray primitive capture; state belongs to the caller until finish. */
|
||||
|
||||
@@ -3277,26 +3277,23 @@ int
|
||||
rt_arb_calc_points(struct rt_arb_internal *arb, int cgtype, const plane_t planes[6], const struct bn_tol *tol)
|
||||
{
|
||||
int i;
|
||||
point_t pt[8];
|
||||
struct rt_arb_internal candidate;
|
||||
|
||||
RT_ARB_CK_MAGIC(arb);
|
||||
candidate = *arb;
|
||||
|
||||
/* find new points for entire solid */
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (rt_arb_3face_intersect(pt[i], planes, cgtype, i*3) < 0) {
|
||||
if (rt_arb_3face_intersect(candidate.pt[i], planes, cgtype, i*3) < 0) {
|
||||
bu_log("rt_arb_calc_points: Intersection of planes fails %d\n", i);
|
||||
return -1; /* FAIL */
|
||||
}
|
||||
}
|
||||
|
||||
/* Move new points to arb tol->dist))*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
VMOVE(arb->pt[i], pt[i]);
|
||||
}
|
||||
|
||||
if (rt_arb_check_points(arb, cgtype, tol) < 0)
|
||||
if (rt_arb_check_points(&candidate, cgtype, tol) < 0)
|
||||
return -1;
|
||||
|
||||
memcpy(arb->pt, candidate.pt, sizeof(arb->pt));
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
@@ -3397,6 +3394,7 @@ rt_arb_calc_planes(struct bu_vls *error_msg_ret,
|
||||
const struct bn_tol *tol)
|
||||
{
|
||||
const int arb_faces[5][24] = rt_arb_faces;
|
||||
plane_t candidate[6];
|
||||
|
||||
/* ARB4 at location 0, ARB5 at 1, etc. */
|
||||
int type = cgtype - ARB4;
|
||||
@@ -3405,6 +3403,7 @@ rt_arb_calc_planes(struct bu_vls *error_msg_ret,
|
||||
|
||||
RT_ARB_CK_MAGIC(arb);
|
||||
BN_CK_TOL(tol);
|
||||
memcpy(candidate, planes, sizeof(candidate));
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (arb_faces[type][i*4] == -1)
|
||||
@@ -3414,7 +3413,7 @@ rt_arb_calc_planes(struct bu_vls *error_msg_ret,
|
||||
int p2 = arb_faces[type][i*4+1];
|
||||
int p3 = arb_faces[type][i*4+2];
|
||||
|
||||
if (bg_make_plane_3pnts(planes[i],
|
||||
if (bg_make_plane_3pnts(candidate[i],
|
||||
arb->pt[p1],
|
||||
arb->pt[p2],
|
||||
arb->pt[p3],
|
||||
@@ -3425,6 +3424,7 @@ rt_arb_calc_planes(struct bu_vls *error_msg_ret,
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(planes, candidate, sizeof(candidate));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1169,6 +1169,17 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Intersections and plane updates can fail after changing several points. */
|
||||
struct rt_arb_internal *original_arb = arb;
|
||||
plane_t *original_planes = planes;
|
||||
struct rt_arb_internal candidate = *arb;
|
||||
plane_t candidate_planes[6];
|
||||
vect_t edit_position;
|
||||
memcpy(candidate_planes, planes, sizeof(candidate_planes));
|
||||
VMOVE(edit_position, pos_model);
|
||||
arb = &candidate;
|
||||
planes = candidate_planes;
|
||||
|
||||
/* set the pointer */
|
||||
switch (arb_type) {
|
||||
case ARB4:
|
||||
@@ -1246,7 +1257,7 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
|
||||
/* do the arb editing */
|
||||
if (edit_class == RT_ARB_EDIT_POINT) {
|
||||
/* moving a point - not an edge */
|
||||
VMOVE(arb->pt[edit_type], pos_model);
|
||||
VMOVE(arb->pt[edit_type], edit_position);
|
||||
edptr += 4;
|
||||
} else if (edit_class == RT_ARB_EDIT_EDGE) {
|
||||
vect_t edge_dir;
|
||||
@@ -1256,8 +1267,8 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
|
||||
pt2 = *edptr++;
|
||||
|
||||
if (flags & RT_ARB_EDIT_EDGE_DIR) {
|
||||
VMOVE(edge_dir, pos_model);
|
||||
VMOVE(pos_model, arb->pt[pt1]);
|
||||
VMOVE(edge_dir, edit_position);
|
||||
VMOVE(edit_position, arb->pt[pt1]);
|
||||
} else {
|
||||
/* calculate edge direction */
|
||||
VSUB2(edge_dir, arb->pt[pt2], arb->pt[pt1]);
|
||||
@@ -1271,7 +1282,7 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
|
||||
bp2 = *edptr++;
|
||||
|
||||
/* move the edge */
|
||||
if (rt_arb_move_edge(error_msg_ret, arb, pos_model, bp1, bp2, pt1, pt2,
|
||||
if (rt_arb_move_edge(error_msg_ret, arb, edit_position, bp1, bp2, pt1, pt2,
|
||||
edge_dir, planes, tol))
|
||||
goto err;
|
||||
}
|
||||
@@ -1377,6 +1388,8 @@ rt_arb_edit(struct bu_vls *error_msg_ret,
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(original_arb->pt, candidate.pt, sizeof(candidate.pt));
|
||||
memcpy(original_planes, candidate_planes, sizeof(candidate_planes));
|
||||
return 0; /* OK */
|
||||
|
||||
err:
|
||||
@@ -1501,6 +1514,48 @@ edarb_canonicalize(struct rt_edit *s, struct rt_arb_internal *arb)
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
arb_move_face_to_point(struct rt_edit *s, const point_t target)
|
||||
{
|
||||
struct rt_arb8_edit *a = (struct rt_arb8_edit *)s->ipe_ptr;
|
||||
struct rt_arb_internal *arb = (struct rt_arb_internal *)s->es_int.idb_ptr;
|
||||
struct rt_arb_internal candidate;
|
||||
plane_t planes[6];
|
||||
struct bu_vls error_msg = BU_VLS_INIT_ZERO;
|
||||
int arb_type;
|
||||
|
||||
RT_ARB_CK_MAGIC(arb);
|
||||
if (a->edit_menu < 0 || a->edit_menu >= ARB8_FACE_COUNT) {
|
||||
bu_vls_printf(s->log_str, "Invalid ARB face index %d\n", a->edit_menu);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
candidate = *arb;
|
||||
memcpy(planes, a->es_peqn, sizeof(planes));
|
||||
planes[a->edit_menu][W] = VDOT(planes[a->edit_menu], target);
|
||||
arb_type = rt_arb_edit_type(s->log_str, s, arb, 0, s->tol);
|
||||
if (!arb_type)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
if (rt_arb_calc_points(&candidate, arb_type, (const plane_t *)planes, s->tol)) {
|
||||
bu_vls_printf(s->log_str, "Cannot calculate ARB points\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
if (edarb_canonicalize(s, &candidate) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
if (rt_arb_calc_planes(&error_msg, &candidate, arb_type, planes, s->tol)) {
|
||||
bu_vls_printf(s->log_str, "%s", bu_vls_cstr(&error_msg));
|
||||
bu_vls_free(&error_msg);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
bu_vls_free(&error_msg);
|
||||
|
||||
memcpy(arb->pt, candidate.pt, sizeof(arb->pt));
|
||||
memcpy(a->es_peqn, planes, sizeof(planes));
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
arb_numeric_target(point_t target, struct rt_edit *s, int *edit_menu)
|
||||
{
|
||||
@@ -1535,38 +1590,13 @@ ecmd_arb_move_face(struct rt_edit *s)
|
||||
{
|
||||
struct rt_arb8_edit *a = (struct rt_arb8_edit *)s->ipe_ptr;
|
||||
|
||||
/* move face through definite point */
|
||||
if (s->e_inpara) {
|
||||
if (!s->e_inpara)
|
||||
return BRLCAD_OK;
|
||||
|
||||
vect_t work;
|
||||
if (arb_numeric_target(work, s, &a->edit_menu) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
if (a->edit_menu < 0 || a->edit_menu >= ARB8_FACE_COUNT) {
|
||||
bu_vls_printf(s->log_str, "Invalid ARB face index %d\n", a->edit_menu);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
struct rt_arb_internal *arb = (struct rt_arb_internal *)s->es_int.idb_ptr;
|
||||
RT_ARB_CK_MAGIC(arb);
|
||||
|
||||
/* change D of planar equation */
|
||||
a->es_peqn[a->edit_menu][W]=VDOT(&a->es_peqn[a->edit_menu][0], work);
|
||||
/* find new vertices, put in record in vector notation */
|
||||
|
||||
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_points(arb, arb_type, (const plane_t *)a->es_peqn, s->tol)) {
|
||||
bu_vls_printf(s->log_str, "Cannot calculate ARB8 points\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
if (edarb_canonicalize(s, arb) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
point_t target;
|
||||
if (arb_numeric_target(target, s, &a->edit_menu) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
return arb_move_face_to_point(s, target);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1757,11 +1787,16 @@ ecmd_arb_rotate_face(struct rt_edit *s)
|
||||
if (arb_type == 0)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
(void)rt_arb_calc_points(arb, arb_type, (const plane_t *)a->es_peqn, s->tol);
|
||||
|
||||
if (rt_arb_calc_points(arb, arb_type, (const plane_t *)a->es_peqn, s->tol)) {
|
||||
bu_vls_printf(s->log_str, "Cannot calculate ARB points\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
if (edarb_canonicalize(s, arb) != BRLCAD_OK) {
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
if (rt_arb_calc_planes(s->log_str, arb, arb_type, a->es_peqn, s->tol))
|
||||
return BRLCAD_ERROR;
|
||||
MAT_IDN(s->incr_change);
|
||||
|
||||
s->e_inpara = 0;
|
||||
@@ -1850,7 +1885,6 @@ arb_mouse_move_element(struct rt_edit *s, const vect_t mousevec)
|
||||
static int
|
||||
edarb_move_face_mousevec(struct rt_edit *s, const vect_t mousevec)
|
||||
{
|
||||
struct rt_arb8_edit *a = (struct rt_arb8_edit *)s->ipe_ptr;
|
||||
vect_t pos_view = VINIT_ZERO; /* Unrotated view space pos */
|
||||
vect_t temp = VINIT_ZERO;
|
||||
vect_t pos_model = VINIT_ZERO; /* Rotated screen space pos */
|
||||
@@ -1859,24 +1893,7 @@ edarb_move_face_mousevec(struct rt_edit *s, const vect_t mousevec)
|
||||
pos_view[Y] = mousevec[Y];
|
||||
MAT4X3PNT(temp, s->vp->gv_view2model, pos_view);
|
||||
MAT4X3PNT(pos_model, s->e_invmat, temp);
|
||||
if (a->edit_menu < 0 || a->edit_menu >= ARB8_FACE_COUNT) {
|
||||
bu_vls_printf(s->log_str, "Invalid ARB face index %d\n", a->edit_menu);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
/* change D of planar equation */
|
||||
a->es_peqn[a->edit_menu][W]=VDOT(&a->es_peqn[a->edit_menu][0], pos_model);
|
||||
struct rt_arb_internal *arb =
|
||||
(struct rt_arb_internal *)s->es_int.idb_ptr;
|
||||
RT_ARB_CK_MAGIC(arb);
|
||||
|
||||
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_points(arb, arb_type, (const plane_t *)a->es_peqn, s->tol)) {
|
||||
bu_vls_printf(s->log_str, "Cannot calculate ARB8 points\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
if (edarb_canonicalize(s, arb) != BRLCAD_OK)
|
||||
if (arb_move_face_to_point(s, pos_model) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
edit_abs_tra(s, pos_view);
|
||||
return BRLCAD_OK;
|
||||
@@ -1889,13 +1906,27 @@ rt_edit_arb_edit(struct rt_edit *s)
|
||||
struct rt_arb_internal *arb = (struct rt_arb_internal *)s->es_int.idb_ptr;
|
||||
struct rt_arb8_edit *a = (struct rt_arb8_edit *)s->ipe_ptr;
|
||||
RT_ARB_CK_MAGIC(arb);
|
||||
struct rt_arb_internal original_arb = *arb;
|
||||
plane_t original_planes[6];
|
||||
memcpy(original_planes, a->es_peqn, sizeof(original_planes));
|
||||
int ret = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1917,22 +1948,38 @@ 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:
|
||||
ecmd_arb_setup_rotface(s);
|
||||
break;
|
||||
case ECMD_ARB_ROTATE_FACE:
|
||||
{
|
||||
mat_t original_acc_rot, original_model_changes, original_incr_change;
|
||||
int original_menu = a->edit_menu;
|
||||
int original_fixv = a->fixv;
|
||||
MAT_COPY(original_acc_rot, s->acc_rot_sol);
|
||||
MAT_COPY(original_model_changes, s->model_changes);
|
||||
MAT_COPY(original_incr_change, s->incr_change);
|
||||
ret = ecmd_arb_rotate_face(s);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
memcpy(arb->pt, original_arb.pt, sizeof(arb->pt));
|
||||
memcpy(a->es_peqn, original_planes, sizeof(original_planes));
|
||||
MAT_COPY(s->acc_rot_sol, original_acc_rot);
|
||||
MAT_COPY(s->model_changes, original_model_changes);
|
||||
MAT_COPY(s->incr_change, original_incr_change);
|
||||
a->edit_menu = original_menu;
|
||||
a->fixv = original_fixv;
|
||||
return ret;
|
||||
}
|
||||
/* The plane is current; bypass arb_planecalc below. */
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
case PTARB: /* move an ARB point */
|
||||
case EARB: /* edit an ARB edge */
|
||||
return edit_arb_element(s);
|
||||
@@ -1942,19 +1989,34 @@ rt_edit_arb_edit(struct rt_edit *s)
|
||||
|
||||
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) {
|
||||
return BRLCAD_ERROR;
|
||||
goto arb_failed;
|
||||
}
|
||||
|
||||
/* must re-calculate the face plane equations for arbs */
|
||||
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) < 0)
|
||||
goto arb_failed;
|
||||
if (rt_arb_calc_planes(&error_msg, arb, arb_type, a->es_peqn, s->tol) < 0) {
|
||||
bu_vls_printf(s->log_str, "%s", bu_vls_cstr(&error_msg));
|
||||
bu_vls_free(&error_msg);
|
||||
goto arb_failed;
|
||||
}
|
||||
bu_vls_free(&error_msg);
|
||||
|
||||
return ret;
|
||||
|
||||
arb_failed:
|
||||
memcpy(arb->pt, original_arb.pt, sizeof(arb->pt));
|
||||
memcpy(a->es_peqn, original_planes, sizeof(original_planes));
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
C_DECL int
|
||||
|
||||
@@ -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);
|
||||
@@ -608,6 +609,21 @@ ecmd_bot_movev_list(struct rt_edit *s)
|
||||
* triangles that share the new vertex.
|
||||
* No e_para needed.
|
||||
*/
|
||||
static int
|
||||
bot_face_edge_other(const int *face, int v0, int v1)
|
||||
{
|
||||
if ((face[0] == v0 && face[1] == v1) ||
|
||||
(face[0] == v1 && face[1] == v0))
|
||||
return face[2];
|
||||
if ((face[1] == v0 && face[2] == v1) ||
|
||||
(face[1] == v1 && face[2] == v0))
|
||||
return face[0];
|
||||
if ((face[2] == v0 && face[0] == v1) ||
|
||||
(face[2] == v1 && face[0] == v0))
|
||||
return face[1];
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
ecmd_bot_esplit(struct rt_edit *s)
|
||||
{
|
||||
@@ -618,13 +634,25 @@ ecmd_bot_esplit(struct rt_edit *s)
|
||||
|
||||
int v0 = b->bot_verts[0];
|
||||
int v1 = b->bot_verts[1];
|
||||
if (v0 < 0 || v1 < 0 || b->bot_verts[2] >= 0) {
|
||||
if (v0 < 0 || v1 < 0 || v0 == v1 ||
|
||||
(size_t)v0 >= bot->num_vertices || (size_t)v1 >= bot->num_vertices ||
|
||||
b->bot_verts[2] >= 0) {
|
||||
bu_vls_printf(s->log_str,
|
||||
"ERROR: ECMD_BOT_ESPLIT requires a single edge selection "
|
||||
"(ECMD_BOT_PICKE first)\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
size_t incident_faces = 0;
|
||||
for (size_t fi = 0; fi < bot->num_faces; fi++) {
|
||||
if (bot_face_edge_other(&bot->faces[fi * 3], v0, v1) >= 0)
|
||||
incident_faces++;
|
||||
}
|
||||
if (!incident_faces) {
|
||||
bu_vls_printf(s->log_str, "ERROR: selected BOT edge was not found\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
/* Compute midpoint */
|
||||
point_t mid;
|
||||
VADD2SCALE(mid, &bot->vertices[v0*3], &bot->vertices[v1*3], 0.5);
|
||||
@@ -642,19 +670,7 @@ ecmd_bot_esplit(struct rt_edit *s)
|
||||
(size_t *)bu_malloc(orig_nf * sizeof(size_t), "split BOT face parents") :
|
||||
NULL;
|
||||
for (size_t fi = 0; fi < orig_nf; fi++) {
|
||||
int f0 = bot->faces[fi*3];
|
||||
int f1 = bot->faces[fi*3+1];
|
||||
int f2 = bot->faces[fi*3+2];
|
||||
|
||||
/* Check whether this face contains the directed or reverse edge */
|
||||
int other = -1;
|
||||
if ((f0 == v0 && f1 == v1) || (f0 == v1 && f1 == v0)) {
|
||||
other = f2;
|
||||
} else if ((f1 == v0 && f2 == v1) || (f1 == v1 && f2 == v0)) {
|
||||
other = f0;
|
||||
} else if ((f2 == v0 && f0 == v1) || (f2 == v1 && f0 == v0)) {
|
||||
other = f1;
|
||||
}
|
||||
int other = bot_face_edge_other(&bot->faces[fi * 3], v0, v1);
|
||||
if (other < 0)
|
||||
continue; /* edge not in this face */
|
||||
|
||||
@@ -1099,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 {
|
||||
|
||||
@@ -174,7 +174,7 @@ cline_scale(struct rt_edit *s)
|
||||
int
|
||||
ecmd_cline_move_h(struct rt_edit *s)
|
||||
{
|
||||
vect_t work;
|
||||
vect_t work, height;
|
||||
point_t model_point;
|
||||
struct rt_cline_internal *cli =
|
||||
(struct rt_cline_internal *)s->es_int.idb_ptr;
|
||||
@@ -182,6 +182,7 @@ ecmd_cline_move_h(struct rt_edit *s)
|
||||
void *d = NULL;
|
||||
|
||||
RT_CLINE_CK_MAGIC(cli);
|
||||
VMOVE(height, cli->h);
|
||||
|
||||
if (s->e_inpara) {
|
||||
if (s->e_inpara != 3) {
|
||||
@@ -194,24 +195,22 @@ ecmd_cline_move_h(struct rt_edit *s)
|
||||
|
||||
if (s->mv_context) {
|
||||
MAT4X3PNT(work, s->e_invmat, model_point);
|
||||
VSUB2(cli->h, work, cli->v);
|
||||
VSUB2(height, work, cli->v);
|
||||
} else
|
||||
VSUB2(cli->h, model_point, cli->v);
|
||||
VSUB2(height, model_point, cli->v);
|
||||
}
|
||||
/* check for zero H vector */
|
||||
if (MAGNITUDE(cli->h) <= SQRT_SMALL_FASTF) {
|
||||
bu_vls_printf(s->log_str, "Zero H vector not allowed, resetting to +Z\n");
|
||||
if (edit_validate_height(s, height) != BRLCAD_OK) {
|
||||
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
|
||||
if (f)
|
||||
(*f)(0, NULL, d, NULL);
|
||||
VSET(cli->h, 0.0, 0.0, 1.0);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
VMOVE(cli->h, height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
static int
|
||||
ecmd_cline_move_h_mousevec(struct rt_edit *s, const vect_t mousevec)
|
||||
{
|
||||
vect_t pos_view = VINIT_ZERO; /* Unrotated view space pos */
|
||||
@@ -228,8 +227,13 @@ ecmd_cline_move_h_mousevec(struct rt_edit *s, const vect_t mousevec)
|
||||
/* Do NOT change pos_view[Z] ! */
|
||||
MAT4X3PNT(temp, s->vp->gv_view2model, pos_view);
|
||||
MAT4X3PNT(tr_temp, s->e_invmat, temp);
|
||||
VSUB2(cli->h, tr_temp, cli->v);
|
||||
vect_t height;
|
||||
VSUB2(height, tr_temp, cli->v);
|
||||
if (edit_validate_height(s, height) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
VMOVE(cli->h, height);
|
||||
edit_abs_tra(s, pos_view);
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
C_DECL int
|
||||
@@ -279,8 +283,7 @@ rt_edit_cline_edit_xy(
|
||||
edit_stra_xy(&pos_view, s, mousevec);
|
||||
break;
|
||||
case ECMD_CLINE_MOVE_H:
|
||||
ecmd_cline_move_h_mousevec(s, mousevec);
|
||||
return BRLCAD_OK;
|
||||
return ecmd_cline_move_h_mousevec(s, mousevec);
|
||||
default:
|
||||
return edit_generic_xy(s, mousevec);
|
||||
}
|
||||
|
||||
@@ -114,6 +114,35 @@ edit_param_read_scalar(fastf_t *out, char **cursor, const char *label,
|
||||
return isfinite(*out) ? BRLCAD_OK : BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
edit_param_read_fields(const char *input, const struct edit_param_field *fields,
|
||||
size_t field_count)
|
||||
{
|
||||
if (!input || !fields || !field_count)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
char *buffer = bu_strdup(input);
|
||||
char *cursor = buffer;
|
||||
int result = BRLCAD_OK;
|
||||
for (size_t i = 0; i < field_count; i++) {
|
||||
const struct edit_param_field *field = &fields[i];
|
||||
if (field->count == ELEMENTS_PER_VECT)
|
||||
result = edit_param_read_vector(field->value, &cursor,
|
||||
field->label, field->conversion);
|
||||
else if (field->count == 1)
|
||||
result = edit_param_read_scalar(field->value, &cursor,
|
||||
field->label, field->conversion);
|
||||
else
|
||||
result = BRLCAD_ERROR;
|
||||
if (result != BRLCAD_OK)
|
||||
break;
|
||||
}
|
||||
if (result == BRLCAD_OK && edit_param_next_line(&cursor))
|
||||
result = BRLCAD_ERROR;
|
||||
bu_free(buffer, "primitive parameter text");
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
edit_repair_parse_options(struct bu_vls *log_str, int argc,
|
||||
const char **argv, const struct bu_opt_desc *options)
|
||||
@@ -194,6 +223,7 @@ edit_sscale(struct rt_edit *s)
|
||||
{
|
||||
mat_t mat, mat1, scalemat;
|
||||
struct rt_db_internal *ip = &s->es_int;
|
||||
fastf_t scale = s->es_scale;
|
||||
|
||||
if (s->e_inpara > 1) {
|
||||
bu_vls_printf(s->log_str, "ERROR: only one argument needed\n");
|
||||
@@ -202,23 +232,37 @@ edit_sscale(struct rt_edit *s)
|
||||
}
|
||||
|
||||
if (s->e_inpara) {
|
||||
/* accumulate the scale factor */
|
||||
s->es_scale = s->e_para[0] / s->acc_sc_sol;
|
||||
s->acc_sc_sol = s->e_para[0];
|
||||
if (!isfinite(s->e_para[0]) || s->e_para[0] <= 0.0 ||
|
||||
!isfinite(s->acc_sc_sol) || s->acc_sc_sol <= 0.0) {
|
||||
bu_vls_printf(s->log_str, "ERROR: scale must be finite and positive\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
scale = s->e_para[0] / s->acc_sc_sol;
|
||||
}
|
||||
|
||||
/* No pending scale operation — nothing to apply. */
|
||||
if (!s->e_inpara && s->es_scale < SMALL_FASTF)
|
||||
|
||||
if (!s->e_inpara && ZERO(scale))
|
||||
return 0;
|
||||
|
||||
bn_mat_scale_about_pnt(scalemat, s->e_keypoint, s->es_scale);
|
||||
if (!isfinite(scale) || scale <= 0.0 ||
|
||||
!OBJ[ip->idb_type].ft_mat ||
|
||||
bn_mat_scale_about_pnt(scalemat, s->e_keypoint, scale)) {
|
||||
bu_vls_printf(s->log_str, "ERROR: cannot apply solid scale\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
bn_mat_mul(mat1, scalemat, s->e_mat);
|
||||
bn_mat_mul(mat, s->e_invmat, mat1);
|
||||
if (OBJ[ip->idb_type].ft_mat)
|
||||
(*OBJ[ip->idb_type].ft_mat)(ip, mat, ip);
|
||||
if ((*OBJ[ip->idb_type].ft_mat)(ip, mat, ip)) {
|
||||
bu_vls_printf(s->log_str, "ERROR: solid scale failed\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
/* reset solid scale factor */
|
||||
s->es_scale = 1.0;
|
||||
if (s->e_inpara)
|
||||
s->acc_sc_sol = s->e_para[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -312,6 +356,19 @@ edit_scale_equal_axes(struct rt_edit *s, vect_t a, vect_t b, vect_t c)
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
int
|
||||
edit_validate_height(struct rt_edit *s, const vect_t height)
|
||||
{
|
||||
fastf_t length = MAGNITUDE(height);
|
||||
fastf_t min_length = s->tol ? fmax(s->tol->dist, SQRT_SMALL_FASTF) :
|
||||
SQRT_SMALL_FASTF;
|
||||
if (!isfinite(length) || length <= min_length) {
|
||||
bu_vls_printf(s->log_str, "Zero or invalid H vector not allowed\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
void
|
||||
edit_stra(struct rt_edit *s)
|
||||
{
|
||||
@@ -467,8 +524,7 @@ edit_generic(
|
||||
switch (s->edit_flag) {
|
||||
case RT_PARAMS_EDIT_SCALE:
|
||||
/* scale the solid uniformly about its vertex point */
|
||||
edit_sscale(s);
|
||||
return BRLCAD_OK;
|
||||
return edit_sscale(s);
|
||||
case RT_PARAMS_EDIT_TRANS:
|
||||
/* translate solid */
|
||||
edit_stra(s);
|
||||
|
||||
@@ -67,6 +67,10 @@ edit_scale_length(struct rt_edit *s, vect_t *axis, fastf_t *scalar);
|
||||
int
|
||||
edit_scale_equal_axes(struct rt_edit *s, vect_t a, vect_t b, vect_t c);
|
||||
|
||||
/* Reject height endpoint edits that would collapse the primitive. */
|
||||
int
|
||||
edit_validate_height(struct rt_edit *s, const vect_t height);
|
||||
|
||||
/* Validate dimension counts before converting numeric edit parameters. */
|
||||
int
|
||||
edit_parse_sample_count(uint32_t *count, fastf_t value);
|
||||
@@ -95,6 +99,17 @@ int
|
||||
edit_param_read_scalar(fastf_t *out, char **cursor, const char *label,
|
||||
fastf_t local2base);
|
||||
|
||||
struct edit_param_field {
|
||||
const char *label;
|
||||
fastf_t *value;
|
||||
int count;
|
||||
fastf_t conversion;
|
||||
};
|
||||
|
||||
int
|
||||
edit_param_read_fields(const char *text, const struct edit_param_field *fields,
|
||||
size_t field_count);
|
||||
|
||||
/* translate solid */
|
||||
void
|
||||
edit_stra(struct rt_edit *s);
|
||||
|
||||
@@ -223,16 +223,6 @@ rt_edit_ehy_write_params(
|
||||
bu_vls_printf(p, "Dist to asymptotes: %.9f\n", ehy->ehy_c * base2local);
|
||||
}
|
||||
|
||||
#define read_params_line_incr \
|
||||
lc = (ln) ? (ln + lcj) : NULL; \
|
||||
if (!lc) { \
|
||||
bu_free(wc, "wc"); \
|
||||
return BRLCAD_ERROR; \
|
||||
} \
|
||||
ln = strchr(lc, tc); \
|
||||
if (ln) *ln = '\0'; \
|
||||
while (lc && strchr(lc, ':')) lc++
|
||||
|
||||
C_DECL int
|
||||
rt_edit_ehy_read_params(
|
||||
struct rt_db_internal *ip,
|
||||
@@ -241,74 +231,22 @@ rt_edit_ehy_read_params(
|
||||
fastf_t local2base
|
||||
)
|
||||
{
|
||||
double a = 0.0;
|
||||
double b = 0.0;
|
||||
double c = 0.0;
|
||||
struct rt_ehy_internal *ehy = (struct rt_ehy_internal *)ip->idb_ptr;
|
||||
RT_EHY_CK_MAGIC(ehy);
|
||||
|
||||
if (!fc)
|
||||
struct rt_ehy_internal candidate = *ehy;
|
||||
const struct edit_param_field fields[] = {
|
||||
{"Vertex", candidate.ehy_V, ELEMENTS_PER_VECT, local2base},
|
||||
{"Height", candidate.ehy_H, ELEMENTS_PER_VECT, local2base},
|
||||
{"Semi-major axis", candidate.ehy_Au, ELEMENTS_PER_VECT, 1.0},
|
||||
{"Semi-major length", &candidate.ehy_r1, 1, local2base},
|
||||
{"Semi-minor length", &candidate.ehy_r2, 1, local2base},
|
||||
{"Dist to asymptotes", &candidate.ehy_c, 1, local2base}
|
||||
};
|
||||
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK ||
|
||||
ZERO(MAGNITUDE(candidate.ehy_Au)))
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
// We're getting the file contents as a string, so we need to split it up
|
||||
// to process lines. See https://stackoverflow.com/a/17983619
|
||||
|
||||
// Figure out if we need to deal with Windows line endings
|
||||
const char *crpos = strchr(fc, '\r');
|
||||
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
|
||||
char tc = (crlf) ? '\r' : '\n';
|
||||
// If we're CRLF jump ahead another character.
|
||||
int lcj = (crlf) ? 2 : 1;
|
||||
|
||||
char *ln = NULL;
|
||||
char *wc = bu_strdup(fc);
|
||||
char *lc = wc;
|
||||
|
||||
// Set up initial line
|
||||
ln = strchr(lc, tc);
|
||||
if (ln) *ln = '\0';
|
||||
|
||||
// Trim off prefixes, if user left them in
|
||||
while (lc && strchr(lc, ':')) lc++;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(ehy->ehy_V, a, b, c);
|
||||
VSCALE(ehy->ehy_V, ehy->ehy_V, local2base);
|
||||
|
||||
// Set up Height line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(ehy->ehy_H, a, b, c);
|
||||
VSCALE(ehy->ehy_H, ehy->ehy_H, local2base);
|
||||
|
||||
// Set up Semi-major axis line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(ehy->ehy_Au, a, b, c);
|
||||
VUNITIZE(ehy->ehy_Au);
|
||||
|
||||
// Set up Semi-major length line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
ehy->ehy_r1 = a * local2base;
|
||||
|
||||
// Set up Semi-minor length line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
ehy->ehy_r2 = a * local2base;
|
||||
|
||||
// Set up distance to asymptotes line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
ehy->ehy_c = a * local2base;
|
||||
|
||||
// Cleanup
|
||||
bu_free(wc, "wc");
|
||||
VUNITIZE(candidate.ehy_Au);
|
||||
*ehy = candidate;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -196,16 +196,6 @@ rt_edit_epa_write_params(
|
||||
bu_vls_printf(p, "Semi-minor length: %.9f\n", epa->epa_r2 * base2local);
|
||||
}
|
||||
|
||||
#define read_params_line_incr \
|
||||
lc = (ln) ? (ln + lcj) : NULL; \
|
||||
if (!lc) { \
|
||||
bu_free(wc, "wc"); \
|
||||
return BRLCAD_ERROR; \
|
||||
} \
|
||||
ln = strchr(lc, tc); \
|
||||
if (ln) *ln = '\0'; \
|
||||
while (lc && strchr(lc, ':')) lc++
|
||||
|
||||
C_DECL int
|
||||
rt_edit_epa_read_params(
|
||||
struct rt_db_internal *ip,
|
||||
@@ -214,68 +204,21 @@ rt_edit_epa_read_params(
|
||||
fastf_t local2base
|
||||
)
|
||||
{
|
||||
double a = 0.0;
|
||||
double b = 0.0;
|
||||
double c = 0.0;
|
||||
struct rt_epa_internal *epa = (struct rt_epa_internal *)ip->idb_ptr;
|
||||
RT_EPA_CK_MAGIC(epa);
|
||||
|
||||
if (!fc)
|
||||
struct rt_epa_internal candidate = *epa;
|
||||
const struct edit_param_field fields[] = {
|
||||
{"Vertex", candidate.epa_V, ELEMENTS_PER_VECT, local2base},
|
||||
{"Height", candidate.epa_H, ELEMENTS_PER_VECT, local2base},
|
||||
{"Semi-major axis", candidate.epa_Au, ELEMENTS_PER_VECT, 1.0},
|
||||
{"Semi-major length", &candidate.epa_r1, 1, local2base},
|
||||
{"Semi-minor length", &candidate.epa_r2, 1, local2base}
|
||||
};
|
||||
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK ||
|
||||
ZERO(MAGNITUDE(candidate.epa_Au)))
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
// We're getting the file contents as a string, so we need to split it up
|
||||
// to process lines. See https://stackoverflow.com/a/17983619
|
||||
|
||||
// Figure out if we need to deal with Windows line endings
|
||||
const char *crpos = strchr(fc, '\r');
|
||||
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
|
||||
char tc = (crlf) ? '\r' : '\n';
|
||||
// If we're CRLF jump ahead another character.
|
||||
int lcj = (crlf) ? 2 : 1;
|
||||
|
||||
char *ln = NULL;
|
||||
char *wc = bu_strdup(fc);
|
||||
char *lc = wc;
|
||||
|
||||
// Set up initial line (Vertex)
|
||||
ln = strchr(lc, tc);
|
||||
if (ln) *ln = '\0';
|
||||
|
||||
// Trim off prefixes, if user left them in
|
||||
while (lc && strchr(lc, ':')) lc++;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(epa->epa_V, a, b, c);
|
||||
VSCALE(epa->epa_V, epa->epa_V, local2base);
|
||||
|
||||
// Set up Height line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(epa->epa_H, a, b, c);
|
||||
VSCALE(epa->epa_H, epa->epa_H, local2base);
|
||||
|
||||
// Set up Semi-major axis line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(epa->epa_Au, a, b, c);
|
||||
VUNITIZE(epa->epa_Au);
|
||||
|
||||
// Set up Semi-major length line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
epa->epa_r1 = a * local2base;
|
||||
|
||||
// Set up Semi-minor length line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
epa->epa_r2 = a * local2base;
|
||||
|
||||
// Cleanup
|
||||
bu_free(wc, "wc");
|
||||
VUNITIZE(candidate.epa_Au);
|
||||
*epa = candidate;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,16 +148,6 @@ rt_edit_eto_write_params(
|
||||
bu_vls_printf(p, "Radius of rotation: %.9f\n", eto->eto_r * base2local);
|
||||
}
|
||||
|
||||
#define read_params_line_incr \
|
||||
lc = (ln) ? (ln + lcj) : NULL; \
|
||||
if (!lc) { \
|
||||
bu_free(wc, "wc"); \
|
||||
return BRLCAD_ERROR; \
|
||||
} \
|
||||
ln = strchr(lc, tc); \
|
||||
if (ln) *ln = '\0'; \
|
||||
while (lc && strchr(lc, ':')) lc++
|
||||
|
||||
C_DECL int
|
||||
rt_edit_eto_read_params(
|
||||
struct rt_db_internal *ip,
|
||||
@@ -166,68 +156,21 @@ rt_edit_eto_read_params(
|
||||
fastf_t local2base
|
||||
)
|
||||
{
|
||||
double a = 0.0;
|
||||
double b = 0.0;
|
||||
double c = 0.0;
|
||||
struct rt_eto_internal *eto = (struct rt_eto_internal *)ip->idb_ptr;
|
||||
RT_ETO_CK_MAGIC(eto);
|
||||
|
||||
if (!fc)
|
||||
struct rt_eto_internal candidate = *eto;
|
||||
const struct edit_param_field fields[] = {
|
||||
{"Vertex", candidate.eto_V, ELEMENTS_PER_VECT, local2base},
|
||||
{"Normal", candidate.eto_N, ELEMENTS_PER_VECT, 1.0},
|
||||
{"Semi-major axis", candidate.eto_C, ELEMENTS_PER_VECT, local2base},
|
||||
{"Semi-minor length", &candidate.eto_rd, 1, local2base},
|
||||
{"Radius of rotation", &candidate.eto_r, 1, local2base}
|
||||
};
|
||||
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK ||
|
||||
ZERO(MAGNITUDE(candidate.eto_N)))
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
// We're getting the file contents as a string, so we need to split it up
|
||||
// to process lines. See https://stackoverflow.com/a/17983619
|
||||
|
||||
// Figure out if we need to deal with Windows line endings
|
||||
const char *crpos = strchr(fc, '\r');
|
||||
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
|
||||
char tc = (crlf) ? '\r' : '\n';
|
||||
// If we're CRLF jump ahead another character.
|
||||
int lcj = (crlf) ? 2 : 1;
|
||||
|
||||
char *ln = NULL;
|
||||
char *wc = bu_strdup(fc);
|
||||
char *lc = wc;
|
||||
|
||||
// Set up initial line (Vertex)
|
||||
ln = strchr(lc, tc);
|
||||
if (ln) *ln = '\0';
|
||||
|
||||
// Trim off prefixes, if user left them in
|
||||
while (lc && strchr(lc, ':')) lc++;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(eto->eto_V, a, b, c);
|
||||
VSCALE(eto->eto_V, eto->eto_V, local2base);
|
||||
|
||||
// Set up Normal line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(eto->eto_N, a, b, c);
|
||||
VUNITIZE(eto->eto_N);
|
||||
|
||||
// Set up Semi-major axis line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(eto->eto_C, a, b, c);
|
||||
VSCALE(eto->eto_C, eto->eto_C, local2base);
|
||||
|
||||
// Set up Semi-minor length line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
eto->eto_rd = a * local2base;
|
||||
|
||||
// Set up Radius of rotation line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
eto->eto_r = a * local2base;
|
||||
|
||||
// Cleanup
|
||||
bu_free(wc, "wc");
|
||||
VUNITIZE(candidate.eto_N);
|
||||
*eto = candidate;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ ecmd_extr_skt_name(struct rt_edit *s)
|
||||
int
|
||||
ecmd_extr_mov_h(struct rt_edit *s)
|
||||
{
|
||||
vect_t work;
|
||||
vect_t work, height;
|
||||
point_t model_point;
|
||||
struct rt_extrude_internal *extr =
|
||||
(struct rt_extrude_internal *)s->es_int.idb_ptr;
|
||||
@@ -256,6 +256,7 @@ ecmd_extr_mov_h(struct rt_edit *s)
|
||||
void *d = NULL;
|
||||
|
||||
RT_EXTRUDE_CK_MAGIC(extr);
|
||||
VMOVE(height, extr->h);
|
||||
if (s->e_inpara) {
|
||||
if (s->e_inpara != 3) {
|
||||
bu_vls_printf(s->log_str, "ERROR: three arguments needed\n");
|
||||
@@ -268,22 +269,20 @@ ecmd_extr_mov_h(struct rt_edit *s)
|
||||
if (s->mv_context) {
|
||||
/* apply s->e_invmat to convert to real model coordinates */
|
||||
MAT4X3PNT(work, s->e_invmat, model_point);
|
||||
VSUB2(extr->h, work, extr->V);
|
||||
VSUB2(height, work, extr->V);
|
||||
} else {
|
||||
VSUB2(extr->h, model_point, extr->V);
|
||||
VSUB2(height, model_point, extr->V);
|
||||
}
|
||||
}
|
||||
|
||||
/* check for zero H vector */
|
||||
if (MAGNITUDE(extr->h) <= SQRT_SMALL_FASTF) {
|
||||
bu_vls_printf(s->log_str, "Zero H vector not allowed, resetting to +Z\n");
|
||||
if (edit_validate_height(s, height) != BRLCAD_OK) {
|
||||
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
|
||||
if (f)
|
||||
(*f)(0, NULL, d, NULL);
|
||||
VSET(extr->h, 0.0, 0.0, 1.0);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
VMOVE(extr->h, height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -380,7 +379,7 @@ ecmd_extr_rot_h(struct rt_edit *s)
|
||||
}
|
||||
|
||||
/* Use mouse to change location of point V+H */
|
||||
void
|
||||
static int
|
||||
ecmd_extr_mov_h_mousevec(struct rt_edit *s, const vect_t mousevec)
|
||||
{
|
||||
vect_t pos_view = VINIT_ZERO; /* Unrotated view space pos */
|
||||
@@ -396,8 +395,13 @@ ecmd_extr_mov_h_mousevec(struct rt_edit *s, const vect_t mousevec)
|
||||
/* Do NOT change pos_view[Z] ! */
|
||||
MAT4X3PNT(temp, s->vp->gv_view2model, pos_view);
|
||||
MAT4X3PNT(tr_temp, s->e_invmat, temp);
|
||||
VSUB2(extr->h, tr_temp, extr->V);
|
||||
vect_t height;
|
||||
VSUB2(height, tr_temp, extr->V);
|
||||
if (edit_validate_height(s, height) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
VMOVE(extr->h, height);
|
||||
edit_abs_tra(s, pos_view);
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -558,8 +562,7 @@ rt_edit_extrude_edit_xy(
|
||||
edit_stra_xy(&pos_view, s, mousevec);
|
||||
break;
|
||||
case ECMD_EXTR_MOV_H:
|
||||
ecmd_extr_mov_h_mousevec(s, mousevec);
|
||||
return BRLCAD_OK;
|
||||
return ecmd_extr_mov_h_mousevec(s, mousevec);
|
||||
default:
|
||||
return edit_generic_xy(s, mousevec);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -155,16 +155,6 @@ rt_edit_hyp_write_params(
|
||||
bu_vls_printf(p, "Ratio of Neck to Base: %.9f\n", hyp->hyp_bnr);
|
||||
}
|
||||
|
||||
#define read_params_line_incr \
|
||||
lc = (ln) ? (ln + lcj) : NULL; \
|
||||
if (!lc) { \
|
||||
bu_free(wc, "wc"); \
|
||||
return BRLCAD_ERROR; \
|
||||
} \
|
||||
ln = strchr(lc, tc); \
|
||||
if (ln) *ln = '\0'; \
|
||||
while (lc && strchr(lc, ':')) lc++
|
||||
|
||||
C_DECL int
|
||||
rt_edit_hyp_read_params(
|
||||
struct rt_db_internal *ip,
|
||||
@@ -173,68 +163,19 @@ rt_edit_hyp_read_params(
|
||||
fastf_t local2base
|
||||
)
|
||||
{
|
||||
double a = 0.0;
|
||||
double b = 0.0;
|
||||
double c = 0.0;
|
||||
struct rt_hyp_internal *hyp = (struct rt_hyp_internal *)ip->idb_ptr;
|
||||
RT_HYP_CK_MAGIC(hyp);
|
||||
|
||||
if (!fc)
|
||||
struct rt_hyp_internal candidate = *hyp;
|
||||
const struct edit_param_field fields[] = {
|
||||
{"Vertex", candidate.hyp_Vi, ELEMENTS_PER_VECT, local2base},
|
||||
{"Height", candidate.hyp_Hi, ELEMENTS_PER_VECT, local2base},
|
||||
{"Semi-major axis", candidate.hyp_A, ELEMENTS_PER_VECT, local2base},
|
||||
{"Semi-minor length", &candidate.hyp_b, 1, local2base},
|
||||
{"Ratio of Neck to Base", &candidate.hyp_bnr, 1, 1.0}
|
||||
};
|
||||
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
// We're getting the file contents as a string, so we need to split it up
|
||||
// to process lines. See https://stackoverflow.com/a/17983619
|
||||
|
||||
// Figure out if we need to deal with Windows line endings
|
||||
const char *crpos = strchr(fc, '\r');
|
||||
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
|
||||
char tc = (crlf) ? '\r' : '\n';
|
||||
// If we're CRLF jump ahead another character.
|
||||
int lcj = (crlf) ? 2 : 1;
|
||||
|
||||
char *ln = NULL;
|
||||
char *wc = bu_strdup(fc);
|
||||
char *lc = wc;
|
||||
|
||||
// Set up initial line (Vertex)
|
||||
ln = strchr(lc, tc);
|
||||
if (ln) *ln = '\0';
|
||||
|
||||
// Trim off prefixes, if user left them in
|
||||
while (lc && strchr(lc, ':')) lc++;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(hyp->hyp_Vi, a, b, c);
|
||||
VSCALE(hyp->hyp_Vi, hyp->hyp_Vi, local2base);
|
||||
|
||||
// Set up Height line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(hyp->hyp_Hi, a, b, c);
|
||||
VSCALE(hyp->hyp_Hi, hyp->hyp_Hi, local2base);
|
||||
|
||||
// Set up Semi-major axis line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(hyp->hyp_A, a, b, c);
|
||||
VSCALE(hyp->hyp_A, hyp->hyp_A, local2base);
|
||||
|
||||
// Set up Semi-minor length line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
hyp->hyp_b = a * local2base;
|
||||
|
||||
// Set up Ratio of Neck to Base line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
hyp->hyp_bnr = a;
|
||||
|
||||
// Cleanup
|
||||
bu_free(wc, "wc");
|
||||
*hyp = candidate;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -676,6 +676,52 @@ nmg_edit_target_point(point_t target, const struct rt_edit *s, const point_t loc
|
||||
VMOVE(target, base_point);
|
||||
}
|
||||
|
||||
static int
|
||||
nmg_edit_move_edge(struct rt_edit *s, const point_t new_pt)
|
||||
{
|
||||
struct rt_nmg_edit *n = (struct rt_nmg_edit *)s->ipe_ptr;
|
||||
struct model *original = (struct model *)s->es_int.idb_ptr;
|
||||
struct model *candidate;
|
||||
struct nmg_struct_counts counts;
|
||||
uint32_t **candidate_structs;
|
||||
struct edgeuse *candidate_eu;
|
||||
int result;
|
||||
|
||||
if (nmg_find_model(&n->es_eu->l.magic) != original)
|
||||
return 1;
|
||||
|
||||
/* A wire move cannot fail after it starts changing geometry. */
|
||||
if (!nmg_find_fu_of_eu(n->es_eu))
|
||||
return nmg_move_edge_thru_pnt(n->es_eu, new_pt, s->tol);
|
||||
|
||||
candidate = nmg_clone_model(original);
|
||||
if (!candidate)
|
||||
return 1;
|
||||
|
||||
candidate_structs = nmg_m_struct_count(&counts, candidate);
|
||||
candidate_eu = (struct edgeuse *)candidate_structs[n->es_eu->index];
|
||||
NMG_CK_EDGEUSE(candidate_eu);
|
||||
result = nmg_move_edge_thru_pnt(candidate_eu, new_pt, s->tol);
|
||||
if (result) {
|
||||
bu_free(candidate_structs, "NMG candidate structures");
|
||||
nmg_km(candidate);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Clone indices identify the corresponding selections in the new model. */
|
||||
n->es_eu = candidate_eu;
|
||||
if (n->es_v && nmg_find_model(&n->es_v->magic) == original)
|
||||
n->es_v = (struct vertex *)candidate_structs[n->es_v->index];
|
||||
if (n->es_fu && nmg_find_model(&n->es_fu->l.magic) == original)
|
||||
n->es_fu = (struct faceuse *)candidate_structs[n->es_fu->index];
|
||||
if (n->es_s && nmg_find_model(&n->es_s->l.magic) == original)
|
||||
n->es_s = (struct shell *)candidate_structs[n->es_s->index];
|
||||
bu_free(candidate_structs, "NMG candidate structures");
|
||||
s->es_int.idb_ptr = (void *)candidate;
|
||||
nmg_km(original);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ecmd_nmg_emove(struct rt_edit *s)
|
||||
{
|
||||
@@ -747,7 +793,7 @@ ecmd_nmg_emove(struct rt_edit *s)
|
||||
}
|
||||
}
|
||||
|
||||
if (nmg_move_edge_thru_pnt(n->es_eu, new_pt, s->tol) < 0) {
|
||||
if (nmg_edit_move_edge(s, new_pt)) {
|
||||
bu_vls_printf(s->log_str, "Edge Move: Unable to hit (%g %g %g)\n",
|
||||
V3ARGS(new_pt));
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
@@ -234,7 +234,14 @@ rt_edit_rec_edit(struct rt_edit *s)
|
||||
tgc = (struct rt_tgc_internal *)s->es_int.idb_ptr;
|
||||
RT_TGC_CK_MAGIC(tgc);
|
||||
if (s->e_inpara == 3) {
|
||||
VSCALE(tgc->v, s->e_para, s->local2base);
|
||||
point_t new_v;
|
||||
VSCALE(new_v, s->e_para, s->local2base);
|
||||
if (!isfinite(new_v[X]) || !isfinite(new_v[Y]) ||
|
||||
!isfinite(new_v[Z])) {
|
||||
bu_vls_printf(s->log_str, "ERROR: base center must be finite\n");
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
VMOVE(tgc->v, new_v);
|
||||
}
|
||||
return BRLCAD_OK;
|
||||
|
||||
@@ -244,11 +251,8 @@ rt_edit_rec_edit(struct rt_edit *s)
|
||||
if (s->e_inpara == 3) {
|
||||
vect_t new_h;
|
||||
VSCALE(new_h, s->e_para, s->local2base);
|
||||
if (MAGNITUDE(new_h) < SMALL_FASTF) {
|
||||
bu_vls_printf(s->log_str,
|
||||
"ERROR: H vector must have non-zero length\n");
|
||||
if (edit_validate_height(s, new_h) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
mag_a = MAGNITUDE(tgc->a);
|
||||
mag_b = MAGNITUDE(tgc->b);
|
||||
@@ -281,7 +285,7 @@ rt_edit_rec_edit(struct rt_edit *s)
|
||||
RT_TGC_CK_MAGIC(tgc);
|
||||
if (s->e_inpara == 1) {
|
||||
r = s->e_para[0] * s->local2base;
|
||||
if (r < SMALL_FASTF) {
|
||||
if (!isfinite(r) || r <= 0.0) {
|
||||
bu_vls_printf(s->log_str,
|
||||
"ERROR: radius must be positive\n");
|
||||
return BRLCAD_ERROR;
|
||||
@@ -298,7 +302,7 @@ rt_edit_rec_edit(struct rt_edit *s)
|
||||
RT_TGC_CK_MAGIC(tgc);
|
||||
if (s->e_inpara == 1) {
|
||||
r = s->e_para[0] * s->local2base;
|
||||
if (r < SMALL_FASTF) {
|
||||
if (!isfinite(r) || r <= 0.0) {
|
||||
bu_vls_printf(s->log_str,
|
||||
"ERROR: radius must be positive\n");
|
||||
return BRLCAD_ERROR;
|
||||
@@ -315,7 +319,7 @@ rt_edit_rec_edit(struct rt_edit *s)
|
||||
RT_TGC_CK_MAGIC(tgc);
|
||||
if (s->e_inpara == 1) {
|
||||
r = s->e_para[0] * s->local2base;
|
||||
if (r < SMALL_FASTF) {
|
||||
if (!isfinite(r) || r <= 0.0) {
|
||||
bu_vls_printf(s->log_str,
|
||||
"ERROR: radius must be positive\n");
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
@@ -222,16 +222,6 @@ rt_edit_rhc_write_params(
|
||||
bu_vls_printf(p, "Dist_to_asymptotes: %.9f\n", rhc->rhc_c * base2local);
|
||||
}
|
||||
|
||||
#define read_params_line_incr \
|
||||
lc = (ln) ? (ln + lcj) : NULL; \
|
||||
if (!lc) { \
|
||||
bu_free(wc, "wc"); \
|
||||
return BRLCAD_ERROR; \
|
||||
} \
|
||||
ln = strchr(lc, tc); \
|
||||
if (ln) *ln = '\0'; \
|
||||
while (lc && strchr(lc, ':')) lc++
|
||||
|
||||
C_DECL int
|
||||
rt_edit_rhc_read_params(
|
||||
struct rt_db_internal *ip,
|
||||
@@ -240,68 +230,19 @@ rt_edit_rhc_read_params(
|
||||
fastf_t local2base
|
||||
)
|
||||
{
|
||||
double a = 0.0;
|
||||
double b = 0.0;
|
||||
double c = 0.0;
|
||||
struct rt_rhc_internal *rhc = (struct rt_rhc_internal *)ip->idb_ptr;
|
||||
RT_RHC_CK_MAGIC(rhc);
|
||||
|
||||
if (!fc)
|
||||
struct rt_rhc_internal candidate = *rhc;
|
||||
const struct edit_param_field fields[] = {
|
||||
{"Vertex", candidate.rhc_V, ELEMENTS_PER_VECT, local2base},
|
||||
{"Height", candidate.rhc_H, ELEMENTS_PER_VECT, local2base},
|
||||
{"Breadth", candidate.rhc_B, ELEMENTS_PER_VECT, local2base},
|
||||
{"Half-width", &candidate.rhc_r, 1, local2base},
|
||||
{"Dist_to_asymptotes", &candidate.rhc_c, 1, local2base}
|
||||
};
|
||||
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
// We're getting the file contents as a string, so we need to split it up
|
||||
// to process lines. See https://stackoverflow.com/a/17983619
|
||||
|
||||
// Figure out if we need to deal with Windows line endings
|
||||
const char *crpos = strchr(fc, '\r');
|
||||
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
|
||||
char tc = (crlf) ? '\r' : '\n';
|
||||
// If we're CRLF jump ahead another character.
|
||||
int lcj = (crlf) ? 2 : 1;
|
||||
|
||||
char *ln = NULL;
|
||||
char *wc = bu_strdup(fc);
|
||||
char *lc = wc;
|
||||
|
||||
// Set up initial line (Vertex)
|
||||
ln = strchr(lc, tc);
|
||||
if (ln) *ln = '\0';
|
||||
|
||||
// Trim off prefixes, if user left them in
|
||||
while (lc && strchr(lc, ':')) lc++;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(rhc->rhc_V, a, b, c);
|
||||
VSCALE(rhc->rhc_V, rhc->rhc_V, local2base);
|
||||
|
||||
// Set up Height line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(rhc->rhc_H, a, b, c);
|
||||
VSCALE(rhc->rhc_H, rhc->rhc_H, local2base);
|
||||
|
||||
// Set up Breadth line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(rhc->rhc_B, a, b, c);
|
||||
VSCALE(rhc->rhc_B, rhc->rhc_B, local2base);
|
||||
|
||||
// Set up Half-width line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
rhc->rhc_r = a * local2base;
|
||||
|
||||
// Set up distance to asymptotes line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
rhc->rhc_c = a * local2base;
|
||||
|
||||
// Cleanup
|
||||
bu_free(wc, "wc");
|
||||
*rhc = candidate;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -195,16 +195,6 @@ rt_edit_rpc_write_params(
|
||||
}
|
||||
|
||||
|
||||
#define read_params_line_incr \
|
||||
lc = (ln) ? (ln + lcj) : NULL; \
|
||||
if (!lc) { \
|
||||
bu_free(wc, "wc"); \
|
||||
return BRLCAD_ERROR; \
|
||||
} \
|
||||
ln = strchr(lc, tc); \
|
||||
if (ln) *ln = '\0'; \
|
||||
while (lc && strchr(lc, ':')) lc++
|
||||
|
||||
C_DECL int
|
||||
rt_edit_rpc_read_params(
|
||||
struct rt_db_internal *ip,
|
||||
@@ -213,62 +203,18 @@ rt_edit_rpc_read_params(
|
||||
fastf_t local2base
|
||||
)
|
||||
{
|
||||
double a = 0.0;
|
||||
double b = 0.0;
|
||||
double c = 0.0;
|
||||
struct rt_rpc_internal *rpc = (struct rt_rpc_internal *)ip->idb_ptr;
|
||||
RT_RPC_CK_MAGIC(rpc);
|
||||
|
||||
if (!fc)
|
||||
struct rt_rpc_internal candidate = *rpc;
|
||||
const struct edit_param_field fields[] = {
|
||||
{"Vertex", candidate.rpc_V, ELEMENTS_PER_VECT, local2base},
|
||||
{"Height", candidate.rpc_H, ELEMENTS_PER_VECT, local2base},
|
||||
{"Breadth", candidate.rpc_B, ELEMENTS_PER_VECT, local2base},
|
||||
{"Half-width", &candidate.rpc_r, 1, local2base}
|
||||
};
|
||||
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
// We're getting the file contents as a string, so we need to split it up
|
||||
// to process lines. See https://stackoverflow.com/a/17983619
|
||||
|
||||
// Figure out if we need to deal with Windows line endings
|
||||
const char *crpos = strchr(fc, '\r');
|
||||
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
|
||||
char tc = (crlf) ? '\r' : '\n';
|
||||
// If we're CRLF jump ahead another character.
|
||||
int lcj = (crlf) ? 2 : 1;
|
||||
|
||||
char *ln = NULL;
|
||||
char *wc = bu_strdup(fc);
|
||||
char *lc = wc;
|
||||
|
||||
// Set up initial line (Vertex)
|
||||
ln = strchr(lc, tc);
|
||||
if (ln) *ln = '\0';
|
||||
|
||||
// Trim off prefixes, if user left them in
|
||||
while (lc && strchr(lc, ':')) lc++;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(rpc->rpc_V, a, b, c);
|
||||
VSCALE(rpc->rpc_V, rpc->rpc_V, local2base);
|
||||
|
||||
// Set up Height line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(rpc->rpc_H, a, b, c);
|
||||
VSCALE(rpc->rpc_H, rpc->rpc_H, local2base);
|
||||
|
||||
// Set up Breadth line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(rpc->rpc_B, a, b, c);
|
||||
VSCALE(rpc->rpc_B, rpc->rpc_B, local2base);
|
||||
|
||||
// Set up Half-width line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf", &a);
|
||||
rpc->rpc_r = a * local2base;
|
||||
|
||||
// Cleanup
|
||||
bu_free(wc, "wc");
|
||||
*rpc = candidate;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -460,16 +460,6 @@ rt_edit_tgc_write_params(
|
||||
bu_vls_printf(p, "D: %.9f %.9f %.9f\n", V3BASE2LOCAL(tgc->d));
|
||||
}
|
||||
|
||||
#define read_params_line_incr \
|
||||
lc = (ln) ? (ln + lcj) : NULL; \
|
||||
if (!lc) { \
|
||||
bu_free(wc, "wc"); \
|
||||
return BRLCAD_ERROR; \
|
||||
} \
|
||||
ln = strchr(lc, tc); \
|
||||
if (ln) *ln = '\0'; \
|
||||
while (lc && strchr(lc, ':')) lc++
|
||||
|
||||
C_DECL int
|
||||
rt_edit_tgc_read_params(
|
||||
struct rt_db_internal *ip,
|
||||
@@ -478,77 +468,20 @@ rt_edit_tgc_read_params(
|
||||
fastf_t local2base
|
||||
)
|
||||
{
|
||||
double a = 0.0;
|
||||
double b = 0.0;
|
||||
double c = 0.0;
|
||||
struct rt_tgc_internal *tgc = (struct rt_tgc_internal *)ip->idb_ptr;
|
||||
RT_TGC_CK_MAGIC(tgc);
|
||||
|
||||
if (!fc)
|
||||
struct rt_tgc_internal candidate = *tgc;
|
||||
const struct edit_param_field fields[] = {
|
||||
{"Vertex", candidate.v, ELEMENTS_PER_VECT, local2base},
|
||||
{"Height", candidate.h, ELEMENTS_PER_VECT, local2base},
|
||||
{"A", candidate.a, ELEMENTS_PER_VECT, local2base},
|
||||
{"B", candidate.b, ELEMENTS_PER_VECT, local2base},
|
||||
{"C", candidate.c, ELEMENTS_PER_VECT, local2base},
|
||||
{"D", candidate.d, ELEMENTS_PER_VECT, local2base}
|
||||
};
|
||||
if (edit_param_read_fields(fc, fields, sizeof(fields) / sizeof(fields[0])) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
|
||||
// We're getting the file contents as a string, so we need to split it up
|
||||
// to process lines. See https://stackoverflow.com/a/17983619
|
||||
|
||||
// Figure out if we need to deal with Windows line endings
|
||||
const char *crpos = strchr(fc, '\r');
|
||||
int crlf = (crpos && crpos[1] == '\n') ? 1 : 0;
|
||||
char tc = (crlf) ? '\r' : '\n';
|
||||
// If we're CRLF jump ahead another character.
|
||||
int lcj = (crlf) ? 2 : 1;
|
||||
|
||||
char *ln = NULL;
|
||||
char *wc = bu_strdup(fc);
|
||||
char *lc = wc;
|
||||
|
||||
// Set up initial line (Vertex)
|
||||
ln = strchr(lc, tc);
|
||||
if (ln) *ln = '\0';
|
||||
|
||||
// Trim off prefixes, if user left them in
|
||||
while (lc && strchr(lc, ':')) lc++;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(tgc->v, a, b, c);
|
||||
VSCALE(tgc->v, tgc->v, local2base);
|
||||
|
||||
// Set up Height line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(tgc->h, a, b, c);
|
||||
VSCALE(tgc->h, tgc->h, local2base);
|
||||
|
||||
// Set up A line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(tgc->a, a, b, c);
|
||||
VSCALE(tgc->a, tgc->a, local2base);
|
||||
|
||||
// Set up B line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(tgc->b, a, b, c);
|
||||
VSCALE(tgc->b, tgc->b, local2base);
|
||||
|
||||
// Set up C line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(tgc->c, a, b, c);
|
||||
VSCALE(tgc->c, tgc->c, local2base);
|
||||
|
||||
// Set up D line
|
||||
read_params_line_incr;
|
||||
|
||||
sscanf(lc, "%lf %lf %lf", &a, &b, &c);
|
||||
VSET(tgc->d, a, b, c);
|
||||
VSCALE(tgc->d, tgc->d, local2base);
|
||||
|
||||
// Cleanup
|
||||
bu_free(wc, "wc");
|
||||
*tgc = candidate;
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
@@ -751,7 +684,7 @@ int
|
||||
ecmd_tgc_mv_h(struct rt_edit *s)
|
||||
{
|
||||
float la, lb, lc, ld; /* TGC: length of vectors */
|
||||
vect_t work;
|
||||
vect_t work, height;
|
||||
point_t model_point;
|
||||
struct rt_tgc_internal *tgc =
|
||||
(struct rt_tgc_internal *)s->es_int.idb_ptr;
|
||||
@@ -759,6 +692,7 @@ ecmd_tgc_mv_h(struct rt_edit *s)
|
||||
void *d = NULL;
|
||||
|
||||
RT_TGC_CK_MAGIC(tgc);
|
||||
VMOVE(height, tgc->h);
|
||||
if (s->e_inpara) {
|
||||
if (s->e_inpara != 3) {
|
||||
bu_vls_printf(s->log_str, "ERROR: three arguments needed\n");
|
||||
@@ -771,22 +705,21 @@ ecmd_tgc_mv_h(struct rt_edit *s)
|
||||
if (s->mv_context) {
|
||||
/* apply s->e_invmat to convert to real model coordinates */
|
||||
MAT4X3PNT(work, s->e_invmat, model_point);
|
||||
VSUB2(tgc->h, work, tgc->v);
|
||||
VSUB2(height, work, tgc->v);
|
||||
} else {
|
||||
VSUB2(tgc->h, model_point, tgc->v);
|
||||
VSUB2(height, model_point, tgc->v);
|
||||
}
|
||||
}
|
||||
|
||||
/* check for zero H vector */
|
||||
if (MAGNITUDE(tgc->h) <= SQRT_SMALL_FASTF) {
|
||||
bu_vls_printf(s->log_str, "Zero H vector not allowed, resetting to +Z\n");
|
||||
if (edit_validate_height(s, height) != BRLCAD_OK) {
|
||||
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
|
||||
if (f)
|
||||
(*f)(0, NULL, d, NULL);
|
||||
VSET(tgc->h, 0.0, 0.0, 1.0);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
VMOVE(tgc->h, height);
|
||||
|
||||
/* have new height vector -- redefine rest of tgc */
|
||||
la = MAGNITUDE(tgc->a);
|
||||
lb = MAGNITUDE(tgc->b);
|
||||
@@ -814,7 +747,7 @@ ecmd_tgc_mv_h(struct rt_edit *s)
|
||||
int
|
||||
ecmd_tgc_mv_hh(struct rt_edit *s)
|
||||
{
|
||||
vect_t work;
|
||||
vect_t work, height;
|
||||
point_t model_point;
|
||||
struct rt_tgc_internal *tgc =
|
||||
(struct rt_tgc_internal *)s->es_int.idb_ptr;
|
||||
@@ -822,6 +755,7 @@ ecmd_tgc_mv_hh(struct rt_edit *s)
|
||||
void *d = NULL;
|
||||
|
||||
RT_TGC_CK_MAGIC(tgc);
|
||||
VMOVE(height, tgc->h);
|
||||
if (s->e_inpara) {
|
||||
if (s->e_inpara != 3) {
|
||||
bu_vls_printf(s->log_str, "ERROR: three arguments needed\n");
|
||||
@@ -834,22 +768,20 @@ ecmd_tgc_mv_hh(struct rt_edit *s)
|
||||
if (s->mv_context) {
|
||||
/* apply s->e_invmat to convert to real model coordinates */
|
||||
MAT4X3PNT(work, s->e_invmat, model_point);
|
||||
VSUB2(tgc->h, work, tgc->v);
|
||||
VSUB2(height, work, tgc->v);
|
||||
} else {
|
||||
VSUB2(tgc->h, model_point, tgc->v);
|
||||
VSUB2(height, model_point, tgc->v);
|
||||
}
|
||||
}
|
||||
|
||||
/* check for zero H vector */
|
||||
if (MAGNITUDE(tgc->h) <= SQRT_SMALL_FASTF) {
|
||||
bu_vls_printf(s->log_str, "Zero H vector not allowed, resetting to +Z\n");
|
||||
if (edit_validate_height(s, height) != BRLCAD_OK) {
|
||||
rt_edit_map_clbk_get(&f, &d, s->m, ECMD_PRINT_RESULTS, BU_CLBK_DURING);
|
||||
if (f)
|
||||
(*f)(0, NULL, d, NULL);
|
||||
VSET(tgc->h, 0.0, 0.0, 1.0);
|
||||
return BRLCAD_ERROR;
|
||||
}
|
||||
|
||||
VMOVE(tgc->h, height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1005,7 +937,7 @@ ecmd_tgc_rot_ab(struct rt_edit *s)
|
||||
}
|
||||
|
||||
/* Use mouse to change location of point V+H */
|
||||
void
|
||||
static int
|
||||
ecmd_tgc_mv_h_mousevec(struct rt_edit *s, const vect_t mousevec)
|
||||
{
|
||||
struct rt_tgc_internal *tgc =
|
||||
@@ -1021,8 +953,13 @@ ecmd_tgc_mv_h_mousevec(struct rt_edit *s, const vect_t mousevec)
|
||||
/* Do NOT change pos_view[Z] ! */
|
||||
MAT4X3PNT(temp, s->vp->gv_view2model, pos_view);
|
||||
MAT4X3PNT(tr_temp, s->e_invmat, temp);
|
||||
VSUB2(tgc->h, tr_temp, tgc->v);
|
||||
vect_t height;
|
||||
VSUB2(height, tr_temp, tgc->v);
|
||||
if (edit_validate_height(s, height) != BRLCAD_OK)
|
||||
return BRLCAD_ERROR;
|
||||
VMOVE(tgc->h, height);
|
||||
edit_abs_tra(s, pos_view);
|
||||
return BRLCAD_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1188,8 +1125,7 @@ rt_edit_tgc_edit_xy(
|
||||
break;
|
||||
case ECMD_TGC_MV_H:
|
||||
case ECMD_TGC_MV_HH:
|
||||
ecmd_tgc_mv_h_mousevec(s, mousevec);
|
||||
return BRLCAD_OK;
|
||||
return ecmd_tgc_mv_h_mousevec(s, mousevec);
|
||||
case ECMD_TGC_ROT_H:
|
||||
case ECMD_TGC_ROT_AB:
|
||||
bu_vls_printf(s->log_str, "%s: XY edit undefined in solid edit mode %d\n", EDOBJ[ip->idb_type].ft_label, s->edit_flag);
|
||||
|
||||
+82
-14
@@ -198,11 +198,11 @@ public:
|
||||
const char *skip_setting = std::getenv("LIBRT_RTCMP_SKIP_MISSES");
|
||||
primitive_mode = primitive_setting && bu_strcmp(primitive_setting, "1") == 0;
|
||||
skip_misses = skip_setting && bu_strcmp(skip_setting, "1") == 0;
|
||||
enabled.store(true, std::memory_order_release);
|
||||
healthy.store(true, std::memory_order_release);
|
||||
try {
|
||||
worker = std::thread(&CaptureWriter::write, this);
|
||||
} catch (const std::exception &e) {
|
||||
enabled.store(false, std::memory_order_release);
|
||||
healthy.store(false, std::memory_order_release);
|
||||
bu_log("RT_DEBUG_RTCMP: cannot start writer: %s\n", e.what());
|
||||
std::fclose(file);
|
||||
file = nullptr;
|
||||
@@ -224,8 +224,24 @@ public:
|
||||
bu_log("RT_DEBUG_RTCMP: closing output failed\n");
|
||||
}
|
||||
|
||||
bool active() const { return enabled.load(std::memory_order_acquire); }
|
||||
bool active() const
|
||||
{
|
||||
return healthy.load(std::memory_order_acquire);
|
||||
}
|
||||
bool capturing() const
|
||||
{
|
||||
return active() && recording.load(std::memory_order_acquire);
|
||||
}
|
||||
bool primitives() const { return primitive_mode; }
|
||||
|
||||
int set_recording(bool requested)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
if (requested && !active()) return -1;
|
||||
recording.store(requested, std::memory_order_release);
|
||||
if (!requested) space.notify_all();
|
||||
return 0;
|
||||
}
|
||||
bool omit_misses() const { return skip_misses; }
|
||||
|
||||
int flush()
|
||||
@@ -244,11 +260,11 @@ public:
|
||||
{
|
||||
std::unique_lock<std::mutex> guard(mutex);
|
||||
space.wait(guard, [&] {
|
||||
return !active() || queued.empty() ||
|
||||
return !capturing() || queued.empty() ||
|
||||
(line.size() <= MAX_QUEUED_BYTES &&
|
||||
queued_bytes <= MAX_QUEUED_BYTES - line.size());
|
||||
});
|
||||
if (!active()) return;
|
||||
if (!capturing()) return;
|
||||
|
||||
if (queued.empty()) deadline = std::chrono::steady_clock::now() + FLUSH_DELAY;
|
||||
queued_bytes += line.size();
|
||||
@@ -260,7 +276,8 @@ public:
|
||||
|
||||
void disable(const char *reason)
|
||||
{
|
||||
if (!enabled.exchange(false, std::memory_order_acq_rel)) return;
|
||||
if (!healthy.exchange(false, std::memory_order_acq_rel)) return;
|
||||
recording.store(false, std::memory_order_release);
|
||||
bu_log("RT_DEBUG_RTCMP: %s; capture disabled\n", reason);
|
||||
ready.notify_all();
|
||||
space.notify_all();
|
||||
@@ -305,7 +322,8 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
std::atomic<bool> enabled{false};
|
||||
std::atomic<bool> healthy{false};
|
||||
std::atomic<bool> recording{false};
|
||||
std::mutex mutex;
|
||||
std::condition_variable ready;
|
||||
std::condition_variable space;
|
||||
@@ -323,23 +341,71 @@ private:
|
||||
bool stopping = false;
|
||||
};
|
||||
|
||||
std::atomic<CaptureWriter *> &
|
||||
initialized_writer()
|
||||
{
|
||||
static std::atomic<CaptureWriter *> capture{nullptr};
|
||||
return capture;
|
||||
}
|
||||
|
||||
struct WriterHolder {
|
||||
CaptureWriter capture;
|
||||
|
||||
WriterHolder()
|
||||
{
|
||||
initialized_writer().store(&capture, std::memory_order_release);
|
||||
}
|
||||
|
||||
~WriterHolder()
|
||||
{
|
||||
initialized_writer().store(nullptr, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
CaptureWriter &
|
||||
writer()
|
||||
{
|
||||
static CaptureWriter instance;
|
||||
return instance;
|
||||
static WriterHolder holder;
|
||||
return holder.capture;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" int
|
||||
rt_rtcmp_capture_set_enabled(int enabled)
|
||||
{
|
||||
if (!enabled) {
|
||||
CaptureWriter *capture =
|
||||
initialized_writer().load(std::memory_order_acquire);
|
||||
return capture ? capture->set_recording(false) : 0;
|
||||
}
|
||||
if (!(RT_G_DEBUG & RT_DEBUG_RTCMP)) return -1;
|
||||
try {
|
||||
return writer().set_recording(true);
|
||||
} catch (const std::exception &e) {
|
||||
bu_log("RT_DEBUG_RTCMP: cannot enable capture: %s\n", e.what());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
_rt_rtcmp_capture_ready(void)
|
||||
{
|
||||
try {
|
||||
return writer().capturing();
|
||||
} catch (const std::exception &e) {
|
||||
bu_log("RT_DEBUG_RTCMP: cannot initialize capture: %s\n",
|
||||
e.what());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void *
|
||||
_rt_rtcmp_capture_begin(void)
|
||||
{
|
||||
const char *mode = std::getenv("LIBRT_RTCMP_PRIMITIVES");
|
||||
if (!mode || bu_strcmp(mode, "1") != 0) return nullptr;
|
||||
try {
|
||||
CaptureWriter &capture = writer();
|
||||
return capture.active() && capture.primitives() ? new CaptureState : nullptr;
|
||||
return capture.primitives() ? new CaptureState : nullptr;
|
||||
} catch (const std::exception &e) {
|
||||
writer().disable(e.what());
|
||||
return nullptr;
|
||||
@@ -364,7 +430,8 @@ _rt_rtcmp_capture_finish(void *state, const struct application *ap, const struct
|
||||
std::unique_ptr<CaptureState> shot(static_cast<CaptureState *>(state));
|
||||
try {
|
||||
CaptureWriter &capture = writer();
|
||||
if (!capture.active()) return;
|
||||
if (!(RT_G_DEBUG & RT_DEBUG_RTCMP) ||
|
||||
!capture.capturing()) return;
|
||||
if (capture.omit_misses() && shot->segments.empty() && parts->pt_forw == parts) return;
|
||||
capture.submit(format_shot(ap, parts, &shot->segments));
|
||||
} catch (const std::exception &e) {
|
||||
@@ -385,7 +452,8 @@ _rt_rtcmp_capture(const struct application *ap, const struct partition *parts)
|
||||
|
||||
try {
|
||||
CaptureWriter &capture = writer();
|
||||
if (capture.active()) capture.submit(format_shot(ap, parts));
|
||||
if ((RT_G_DEBUG & RT_DEBUG_RTCMP) && capture.capturing())
|
||||
capture.submit(format_shot(ap, parts));
|
||||
} catch (const std::exception &e) {
|
||||
writer().disable(e.what());
|
||||
}
|
||||
|
||||
+7
-3
@@ -545,6 +545,7 @@ rt_shootray(register struct application *ap)
|
||||
struct resource *resp;
|
||||
struct rt_i *rtip;
|
||||
const int debug_shoot = RT_G_DEBUG & RT_DEBUG_SHOOT;
|
||||
int rtcmp_capture = 0;
|
||||
void *rtcmp_state = NULL;
|
||||
fastf_t pending_hit = 0; /* dist of closest odd hit pending */
|
||||
|
||||
@@ -600,8 +601,11 @@ rt_shootray(register struct application *ap)
|
||||
BU_LIST_INIT(&waiting_segs.l);
|
||||
BU_LIST_INIT(&finished_segs.l);
|
||||
ap->a_finished_segs_hdp = &finished_segs;
|
||||
if (RT_G_DEBUG & RT_DEBUG_RTCMP)
|
||||
rtcmp_state = _rt_rtcmp_capture_begin();
|
||||
if (RT_G_DEBUG & RT_DEBUG_RTCMP) {
|
||||
rtcmp_capture = _rt_rtcmp_capture_ready();
|
||||
if (rtcmp_capture)
|
||||
rtcmp_state = _rt_rtcmp_capture_begin();
|
||||
}
|
||||
|
||||
if (!BU_LIST_IS_INITIALIZED(&resp->re_parthead)) {
|
||||
/* XXX This shouldn't happen any more */
|
||||
@@ -968,7 +972,7 @@ hitit:
|
||||
|
||||
if (rtcmp_state)
|
||||
_rt_rtcmp_capture_finish(rtcmp_state, ap, &FinalPart);
|
||||
else if (RT_G_DEBUG & RT_DEBUG_RTCMP)
|
||||
else if (rtcmp_capture)
|
||||
_rt_rtcmp_capture(ap, &FinalPart);
|
||||
|
||||
/* Before recursing, release storage for unused Initial
|
||||
|
||||
@@ -57,6 +57,7 @@ foreach(edit_case IN LISTS edit_cases)
|
||||
endforeach()
|
||||
|
||||
configure_file(cases.inc.in "${CMAKE_CURRENT_BINARY_DIR}/cases.inc" @ONLY)
|
||||
distclean("${CMAKE_CURRENT_BINARY_DIR}/cases.inc")
|
||||
|
||||
brlcad_addexec(rt_edit_test "${edit_sources}" "librt;libnmg;libwdb;libbrep;${WINSOCK_LIB}" TEST)
|
||||
# The cases have translation-unit-local fixture helpers with shared names.
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -778,6 +851,72 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
|
||||
if (!edit_test_mouse_knobs_match(s, face_view_target))
|
||||
bu_exit(1, "ERROR: ARB8 mouse face knobs missed cursor\n");
|
||||
|
||||
/* A rejected drag must not become the starting geometry for the next. */
|
||||
struct rt_arb_internal valid_face_arb = *arb;
|
||||
plane_t valid_face_planes[ARB8_FACE_COUNT];
|
||||
memcpy(valid_face_planes, a->es_peqn, sizeof(valid_face_planes));
|
||||
s->local2base = 25.4;
|
||||
s->base2local = 1.0 / s->local2base;
|
||||
VSET(mousevec, 1.0, 0.0, 0.0); /* Collapse the moved face onto the opposite face. */
|
||||
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_ERROR ||
|
||||
memcmp(arb->pt, valid_face_arb.pt, sizeof(arb->pt)) ||
|
||||
memcmp(a->es_peqn, valid_face_planes, sizeof(valid_face_planes)))
|
||||
bu_exit(1, "ERROR: rejected ARB8 mouse face move changed edit state\n");
|
||||
|
||||
const fastf_t face_drags[] = {0.3, 0.4, 0.25};
|
||||
const size_t drag_cycles = 32;
|
||||
const size_t drag_positions = sizeof(face_drags) / sizeof(face_drags[0]);
|
||||
for (size_t drag = 0; drag < drag_cycles * drag_positions; drag++) {
|
||||
fastf_t target_x = face_drags[drag % drag_positions];
|
||||
VSET(mousevec, target_x, 0.0, 0.0);
|
||||
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_OK ||
|
||||
rt_edit_process(s) != BRLCAD_OK)
|
||||
bu_exit(1, "ERROR: ARB8 mouse face move failed after rejected drag\n");
|
||||
for (size_t i = 0; i < sizeof(face_points) / sizeof(face_points[0]); i++) {
|
||||
if (!NEAR_EQUAL(arb->pt[face_points[i]][X], target_x, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: repeated ARB8 mouse face move drifted\n");
|
||||
}
|
||||
}
|
||||
|
||||
struct rt_arb_internal before_rejected_calc = *arb;
|
||||
plane_t rejected_planes[ARB8_FACE_COUNT];
|
||||
memcpy(rejected_planes, a->es_peqn, sizeof(rejected_planes));
|
||||
rejected_planes[a->edit_menu][W] = VDOT(rejected_planes[a->edit_menu], arb->pt[1]);
|
||||
if (rt_arb_calc_points(arb, ARB8, (const plane_t *)rejected_planes, s->tol) >= 0 ||
|
||||
memcmp(arb->pt, before_rejected_calc.pt, sizeof(arb->pt)))
|
||||
bu_exit(1, "ERROR: rejected ARB point calculation changed geometry\n");
|
||||
|
||||
struct rt_arb_internal invalid_arb = *arb;
|
||||
VMOVE(invalid_arb.pt[6], invalid_arb.pt[5]);
|
||||
VMOVE(invalid_arb.pt[0], invalid_arb.pt[4]);
|
||||
memcpy(rejected_planes, a->es_peqn, sizeof(rejected_planes));
|
||||
plane_t unchanged_planes[ARB8_FACE_COUNT];
|
||||
memcpy(unchanged_planes, rejected_planes, sizeof(unchanged_planes));
|
||||
struct bu_vls rejected_plane_msg = BU_VLS_INIT_ZERO;
|
||||
if (rt_arb_calc_planes(&rejected_plane_msg, &invalid_arb, ARB8,
|
||||
rejected_planes, s->tol) >= 0 ||
|
||||
memcmp(rejected_planes, unchanged_planes, sizeof(rejected_planes)))
|
||||
bu_exit(1, "ERROR: rejected ARB plane calculation changed planes\n");
|
||||
bu_vls_free(&rejected_plane_msg);
|
||||
|
||||
struct rt_arb_internal before_rejected_edge = *arb;
|
||||
memcpy(rejected_planes, a->es_peqn, sizeof(rejected_planes));
|
||||
VSET(mousevec, 0.0, 1.0, 0.0); /* Move edge 12 onto the opposite edge. */
|
||||
if (rt_arb_edit(s->log_str, arb, NULL, ARB8, 0,
|
||||
RT_ARB_EDIT_DEFAULT, mousevec, rejected_planes, s->tol) == 0 ||
|
||||
memcmp(arb->pt, before_rejected_edge.pt, sizeof(arb->pt)) ||
|
||||
memcmp(rejected_planes, a->es_peqn, sizeof(rejected_planes)))
|
||||
bu_exit(1, "ERROR: rejected ARB edge edit changed geometry or planes\n");
|
||||
|
||||
memcpy(rejected_planes, a->es_peqn, sizeof(rejected_planes));
|
||||
VSETALL(mousevec, 0.0);
|
||||
if (rt_arb_edit(s->log_str, arb, NULL, ARB8, 0,
|
||||
RT_ARB_EDIT_EDGE_DIR, mousevec, rejected_planes, s->tol) == 0 ||
|
||||
!ZERO(MAGNITUDE(mousevec)) ||
|
||||
memcmp(arb->pt, before_rejected_edge.pt, sizeof(arb->pt)) ||
|
||||
memcmp(rejected_planes, a->es_peqn, sizeof(rejected_planes)))
|
||||
bu_exit(1, "ERROR: rejected ARB edge direction changed input or edit state\n");
|
||||
|
||||
s->local2base = 1.0;
|
||||
s->base2local = 1.0;
|
||||
|
||||
@@ -844,6 +983,29 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
|
||||
ZERO(a->es_peqn[4][Y]))
|
||||
bu_exit(1, "ERROR: ARB extended face rotation changed input or left plane unchanged\n");
|
||||
|
||||
arb8_reset(s, arb, a);
|
||||
a->edit_menu = 0; /* Rotate the bottom plane onto a side plane. */
|
||||
a->fixv = 0;
|
||||
rt_edit_set_edflag(s, ECMD_ARB_ROTATE_FACE);
|
||||
s->mv_context = 0;
|
||||
s->e_inpara = 3;
|
||||
VSET(s->e_para, 0.0, 90.0, 0.0);
|
||||
MAT_IDN(s->acc_rot_sol);
|
||||
MAT_IDN(s->model_changes);
|
||||
MAT_IDN(s->incr_change);
|
||||
if (rt_arb_calc_planes(s->log_str, arb, ARB8, a->es_peqn, s->tol))
|
||||
bu_exit(1, "ERROR: ARB rejected-rotation setup failed\n");
|
||||
struct rt_arb_internal before_rejected_rotation = *arb;
|
||||
plane_t before_rotation_planes[ARB8_FACE_COUNT];
|
||||
mat_t before_rotation_acc;
|
||||
memcpy(before_rotation_planes, a->es_peqn, sizeof(before_rotation_planes));
|
||||
MAT_COPY(before_rotation_acc, s->acc_rot_sol);
|
||||
if (rt_edit_process(s) != BRLCAD_ERROR ||
|
||||
memcmp(arb->pt, before_rejected_rotation.pt, sizeof(arb->pt)) ||
|
||||
memcmp(a->es_peqn, before_rotation_planes, sizeof(before_rotation_planes)) ||
|
||||
memcmp(s->acc_rot_sol, before_rotation_acc, sizeof(before_rotation_acc)))
|
||||
bu_exit(1, "ERROR: rejected ARB face rotation changed edit state\n");
|
||||
|
||||
/* The same face operation must survive the interactive rotation knob
|
||||
* adapter, which supplies an incremental matrix rather than parameters.
|
||||
*/
|
||||
@@ -864,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. */
|
||||
|
||||
@@ -402,6 +402,20 @@ rt_edit_test_bot(void)
|
||||
V3ARGS(&bot->vertices[4*3]));
|
||||
}
|
||||
|
||||
bot_reset(s, bot, b);
|
||||
/* An edge selection can become stale after a topology change. */
|
||||
bot->faces[0] = 0; bot->faces[1] = 2; bot->faces[2] = 3;
|
||||
bot->faces[3] = 1; bot->faces[4] = 2; bot->faces[5] = 3;
|
||||
int faces_before[12];
|
||||
memcpy(faces_before, bot->faces, sizeof(faces_before));
|
||||
b->bot_verts[0] = 0;
|
||||
b->bot_verts[1] = 1;
|
||||
EDOBJ[dp->d_minor_type].ft_set_edit_mode(s, ECMD_BOT_ESPLIT);
|
||||
if (rt_edit_process(s) != BRLCAD_ERROR ||
|
||||
bot->num_vertices != 4 || bot->num_faces != 4 ||
|
||||
memcmp(bot->faces, faces_before, sizeof(faces_before)))
|
||||
bu_exit(1, "ERROR: stale BOT edge split changed topology\n");
|
||||
|
||||
/* ================================================================
|
||||
* ECMD_BOT_FSPLIT: split face {0,2,3} of a fresh tetrahedron
|
||||
*
|
||||
@@ -629,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)
|
||||
* ================================================================*/
|
||||
|
||||
@@ -258,6 +258,27 @@ rt_edit_test_cline(void)
|
||||
rt_edit_process(s);
|
||||
if (cline_diff("ECMD_CLINE_MOVE_H", cmp, edit_cline))
|
||||
bu_exit(1, "ERROR: ECMD_CLINE_MOVE_H failed\n");
|
||||
|
||||
cline_reset(s, edit_cline, orig, cmp);
|
||||
s->e_inpara = 3;
|
||||
s->local2base = 25.4;
|
||||
s->base2local = 1.0 / s->local2base;
|
||||
VSCALE(s->e_para, orig->v, s->base2local);
|
||||
if (rt_edit_process(s) != BRLCAD_ERROR ||
|
||||
cline_diff("rejected zero-height move", cmp, edit_cline))
|
||||
bu_exit(1, "ERROR: rejected CLINE height move changed geometry\n");
|
||||
s->local2base = 1.0;
|
||||
s->base2local = 1.0;
|
||||
|
||||
cline_reset(s, edit_cline, orig, cmp);
|
||||
VMOVE(s->curr_e_axes_pos, orig->v);
|
||||
point_t rejected_view_target;
|
||||
MAT4X3PNT(rejected_view_target, v->gv_model2view, orig->v);
|
||||
VMOVE(mousevec, rejected_view_target);
|
||||
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_ERROR ||
|
||||
cline_diff("rejected mouse zero-height move", cmp, edit_cline))
|
||||
bu_exit(1, "ERROR: rejected CLINE mouse height move changed geometry\n");
|
||||
VADD2(s->curr_e_axes_pos, orig->v, orig->h);
|
||||
bu_log("ECMD_CLINE_MOVE_H SUCCESS: h=%g,%g,%g\n", V3ARGS(edit_cline->h));
|
||||
|
||||
/* ================================================================
|
||||
|
||||
@@ -232,6 +232,27 @@ rt_edit_test_extrude(void)
|
||||
rt_edit_process(s);
|
||||
if (extr_diff("ECMD_EXTR_MOV_H", cmp, edit_extr))
|
||||
bu_exit(1, "ERROR: ECMD_EXTR_MOV_H failed\n");
|
||||
|
||||
extr_reset(s, edit_extr, orig, cmp);
|
||||
s->e_inpara = 3;
|
||||
s->local2base = 25.4;
|
||||
s->base2local = 1.0 / s->local2base;
|
||||
VSCALE(s->e_para, orig->V, s->base2local);
|
||||
if (rt_edit_process(s) != BRLCAD_ERROR ||
|
||||
extr_diff("rejected zero-height move", cmp, edit_extr))
|
||||
bu_exit(1, "ERROR: rejected EXTRUDE height move changed geometry\n");
|
||||
s->local2base = 1.0;
|
||||
s->base2local = 1.0;
|
||||
|
||||
extr_reset(s, edit_extr, orig, cmp);
|
||||
VMOVE(s->curr_e_axes_pos, orig->V);
|
||||
point_t rejected_view_target;
|
||||
MAT4X3PNT(rejected_view_target, v->gv_model2view, orig->V);
|
||||
VMOVE(mousevec, rejected_view_target);
|
||||
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_ERROR ||
|
||||
extr_diff("rejected mouse zero-height move", cmp, edit_extr))
|
||||
bu_exit(1, "ERROR: rejected EXTRUDE mouse height move changed geometry\n");
|
||||
VADD2(s->curr_e_axes_pos, orig->V, orig->h);
|
||||
bu_log("ECMD_EXTR_MOV_H SUCCESS: h=%g,%g,%g\n", V3ARGS(edit_extr->h));
|
||||
|
||||
/* ================================================================
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -144,16 +144,66 @@ check_unit(fastf_t local2base, const char *unit)
|
||||
rt_edit_checkpoint(edit) != BRLCAD_OK)
|
||||
++failures;
|
||||
|
||||
uint8_t *saved_checkpoint = edit->es_ckpt.ext_buf;
|
||||
size_t saved_size = edit->es_ckpt.ext_nbytes;
|
||||
/* Force export failure without altering the saved checkpoint. */
|
||||
edit->es_int.idb_type = -1;
|
||||
int checkpoint_result = rt_edit_checkpoint(edit);
|
||||
edit->es_int.idb_type = ID_ELL;
|
||||
if (checkpoint_result != BRLCAD_ERROR ||
|
||||
edit->es_ckpt.ext_buf != saved_checkpoint ||
|
||||
edit->es_ckpt.ext_nbytes != saved_size || !same_ell(edit, 4))
|
||||
++failures;
|
||||
|
||||
/* This placeholder has no importer; failed revert must preserve ELL. */
|
||||
edit->es_int.idb_type = ID_UNUSED1;
|
||||
int revert_result = rt_edit_revert(edit);
|
||||
edit->es_int.idb_type = ID_ELL;
|
||||
if (revert_result != BRLCAD_ERROR || !same_ell(edit, 4) ||
|
||||
edit->es_ckpt.ext_buf != saved_checkpoint)
|
||||
++failures;
|
||||
bu_log("failed checkpoint/revert preserve state\t%s\t%s\n", unit,
|
||||
failures ? "fail" : "pass");
|
||||
|
||||
rt_edit_set_edflag(edit, RT_PARAMS_EDIT_SCALE);
|
||||
edit->update_views = 0;
|
||||
edit->e_inpara = 2;
|
||||
edit->e_mvalid = 1;
|
||||
edit->es_scale = 2.0;
|
||||
edit->e_para[0] = 2.0;
|
||||
edit->e_para[1] = 3.0;
|
||||
if (rt_edit_process(edit) != BRLCAD_ERROR ||
|
||||
edit->e_inpara || edit->e_mvalid || !ZERO(edit->es_scale) ||
|
||||
edit->update_views || !EQUAL(edit->e_para[0], 2.0) ||
|
||||
!same_ell(edit, 4))
|
||||
++failures;
|
||||
rt_edit_set_edflag(edit, ECMD_ELL_SCALE_A);
|
||||
if (rt_edit_process(edit) != BRLCAD_OK || !same_ell(edit, 4) ||
|
||||
edit->update_views != 1)
|
||||
++failures;
|
||||
if (rt_edit_process(edit) != BRLCAD_OK || edit->update_views != 1)
|
||||
++failures;
|
||||
bu_log("failed edit consumes input\t%s\t%s\n", unit,
|
||||
failures ? "fail" : "pass");
|
||||
|
||||
const fastf_t target_length = 2.0 * inch_to_mm;
|
||||
rt_edit_set_edflag(edit, ECMD_ELL_SCALE_A);
|
||||
edit->mv_context = 1;
|
||||
edit->e_inpara = 1;
|
||||
edit->e_para[0] = target_length / local2base;
|
||||
if (rt_edit_process(edit) != BRLCAD_OK ||
|
||||
!same_ell(edit, target_length) ||
|
||||
!NEAR_EQUAL(edit->e_para[0], target_length / local2base,
|
||||
VUNITIZE_TOL) ||
|
||||
rt_edit_revert(edit) != BRLCAD_OK || !same_ell(edit, 4))
|
||||
int edit_result = rt_edit_process(edit);
|
||||
bool scaled = same_ell(edit, target_length) &&
|
||||
NEAR_EQUAL(edit->e_para[0], target_length / local2base,
|
||||
VUNITIZE_TOL);
|
||||
edit->acc_sc_sol = 2.5;
|
||||
VSET(edit->e_keypoint, -1, -1, -1);
|
||||
point_t original_keypoint = {10, 5, 20};
|
||||
if (edit_result != BRLCAD_OK || !scaled ||
|
||||
rt_edit_revert(edit) != BRLCAD_OK || !same_ell(edit, 4) ||
|
||||
!EQUAL(edit->acc_sc_sol, 1.0) ||
|
||||
!VNEAR_EQUAL(edit->e_keypoint, original_keypoint, VUNITIZE_TOL))
|
||||
++failures;
|
||||
if (rt_edit_revert(edit) != BRLCAD_OK || !same_ell(edit, 4))
|
||||
++failures;
|
||||
bu_log("checkpoint/edit/revert\t%s\t%s\n", unit,
|
||||
failures ? "fail" : "pass");
|
||||
@@ -194,6 +244,18 @@ int
|
||||
rt_edit_test_lifecycle_matrix(void)
|
||||
{
|
||||
int failures = check_map();
|
||||
struct rt_edit *idle = rt_edit_create(NULL, NULL, NULL, NULL);
|
||||
if (!idle)
|
||||
return BRLCAD_ERROR;
|
||||
idle->e_inpara = 1;
|
||||
idle->e_mvalid = 1;
|
||||
idle->es_scale = 2.0;
|
||||
if (rt_edit_process(NULL) != BRLCAD_ERROR ||
|
||||
rt_edit_process(idle) != BRLCAD_ERROR ||
|
||||
idle->e_inpara || idle->e_mvalid || !ZERO(idle->es_scale) ||
|
||||
idle->update_views)
|
||||
++failures;
|
||||
rt_edit_destroy(idle);
|
||||
failures += check_unit(1.0, "mm");
|
||||
failures += check_unit(inch_to_mm, "in");
|
||||
return failures ? BRLCAD_ERROR : BRLCAD_OK;
|
||||
|
||||
@@ -282,6 +282,29 @@ nmg_tet_state(const struct rt_edit *edit,
|
||||
nmg_points_match(edit, expected, NMG_TET_VERTEX_COUNT);
|
||||
}
|
||||
|
||||
static bool
|
||||
nmg_tet_face_planes(const struct model *model,
|
||||
fastf_t planes[NMG_TET_FACE_COUNT][ELEMENTS_PER_PLANE])
|
||||
{
|
||||
size_t count = 0;
|
||||
struct nmgregion *region;
|
||||
for (BU_LIST_FOR(region, nmgregion, &model->r_hd)) {
|
||||
struct shell *shell;
|
||||
for (BU_LIST_FOR(shell, shell, ®ion->s_hd)) {
|
||||
struct faceuse *face;
|
||||
for (BU_LIST_FOR(face, faceuse, &shell->fu_hd)) {
|
||||
if (face->orientation != OT_SAME)
|
||||
continue;
|
||||
if (count == NMG_TET_FACE_COUNT || !face->f_p->g.plane_p)
|
||||
return false;
|
||||
memcpy(planes[count++], face->f_p->g.plane_p->N,
|
||||
sizeof(plane_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
return count == NMG_TET_FACE_COUNT;
|
||||
}
|
||||
|
||||
static int
|
||||
nmg_tet_step(struct rt_edit *edit, const char *unit, const char *name,
|
||||
int command, const fastf_t *params, int count,
|
||||
@@ -354,6 +377,34 @@ nmg_operation_matrix_unit(fastf_t local2base, const char *unit)
|
||||
ECMD_NMG_EKILL, NULL, 0, expected, -1, false, true);
|
||||
failures += nmg_tet_step(edit, unit, "reject extrusion without loop",
|
||||
ECMD_NMG_LEXTRU_DIR, extrude_direction, 4, expected, -1, false, true);
|
||||
|
||||
/* A target at the opposite face vertex makes its new plane degenerate. */
|
||||
struct rt_nmg_edit *selection = (struct rt_nmg_edit *)edit->ipe_ptr;
|
||||
struct model *model = (struct model *)edit->es_int.idb_ptr;
|
||||
struct nmgregion *region = BU_LIST_FIRST(nmgregion, &model->r_hd);
|
||||
struct shell *shell = BU_LIST_FIRST(shell, ®ion->s_hd);
|
||||
struct faceuse *face = BU_LIST_FIRST(faceuse, &shell->fu_hd);
|
||||
if (face->orientation != OT_SAME)
|
||||
face = face->fumate_p;
|
||||
struct loopuse *loop = BU_LIST_FIRST(loopuse, &face->lu_hd);
|
||||
selection->es_eu = BU_LIST_FIRST(edgeuse, &loop->down_hd);
|
||||
struct edgeuse *next = BU_LIST_PNEXT_CIRC(edgeuse, &selection->es_eu->l);
|
||||
point_t degenerate_target;
|
||||
VSCALE(degenerate_target, next->eumate_p->vu_p->v_p->vg_p->coord,
|
||||
1.0 / local2base);
|
||||
fastf_t before_planes[NMG_TET_FACE_COUNT][ELEMENTS_PER_PLANE];
|
||||
fastf_t after_planes[NMG_TET_FACE_COUNT][ELEMENTS_PER_PLANE];
|
||||
bool have_planes = nmg_tet_face_planes(model, before_planes);
|
||||
failures += nmg_tet_step(edit, unit, "reject degenerate edge move",
|
||||
ECMD_NMG_EMOVE, degenerate_target, 3, expected, -1, false, true);
|
||||
if (!have_planes || !nmg_tet_face_planes(
|
||||
(struct model *)edit->es_int.idb_ptr, after_planes) ||
|
||||
memcmp(before_planes, after_planes, sizeof(before_planes))) {
|
||||
bu_log("nmg\treject degenerate edge move planes\t%s\tfail\n", unit);
|
||||
++failures;
|
||||
}
|
||||
selection->es_eu = NULL;
|
||||
|
||||
failures += nmg_tet_step(edit, unit, "reject fractional vertex index",
|
||||
ECMD_NMG_VPICK, bad_pick, 1, expected, -1, false, true);
|
||||
failures += nmg_tet_step(edit, unit, "pick vertex",
|
||||
@@ -375,6 +426,45 @@ nmg_operation_matrix_unit(fastf_t local2base, const char *unit)
|
||||
failures += nmg_tet_step(edit, unit, "move face",
|
||||
ECMD_NMG_FMOVE, face_delta, 3, expected, 1, true);
|
||||
|
||||
/* A successful face-edge move must remap all live NMG selections. */
|
||||
model = (struct model *)edit->es_int.idb_ptr;
|
||||
region = BU_LIST_FIRST(nmgregion, &model->r_hd);
|
||||
shell = BU_LIST_FIRST(shell, ®ion->s_hd);
|
||||
face = BU_LIST_FIRST(faceuse, &shell->fu_hd);
|
||||
if (face->orientation != OT_SAME)
|
||||
face = face->fumate_p;
|
||||
loop = BU_LIST_FIRST(loopuse, &face->lu_hd);
|
||||
selection->es_eu = BU_LIST_FIRST(edgeuse, &loop->down_hd);
|
||||
point_t edge_target;
|
||||
VMOVE(edge_target, selection->es_eu->vu_p->v_p->vg_p->coord);
|
||||
edge_target[Y] += 0.1;
|
||||
edge_target[Z] += 0.1;
|
||||
rt_edit_set_edflag(edit, ECMD_NMG_EMOVE);
|
||||
edit->e_inpara = 3;
|
||||
VSCALE(edit->e_para, edge_target, 1.0 / local2base);
|
||||
int edge_result = rt_edit_process(edit);
|
||||
struct model *moved_model = (struct model *)edit->es_int.idb_ptr;
|
||||
if (edge_result != BRLCAD_OK || moved_model == model ||
|
||||
nmg_find_model(&selection->es_eu->l.magic) != moved_model ||
|
||||
nmg_find_model(&selection->es_v->magic) != moved_model ||
|
||||
nmg_find_model(&selection->es_fu->l.magic) != moved_model) {
|
||||
bu_log("nmg\tmove face edge and remap selections\t%s\tfail\n", unit);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (rt_edit_checkpoint(edit) != BRLCAD_OK) {
|
||||
bu_log("nmg\tcheckpoint selected model\t%s\tfail\n", unit);
|
||||
++failures;
|
||||
} else {
|
||||
selection->es_v->vg_p->coord[X] += 1.0;
|
||||
if (rt_edit_revert(edit) != BRLCAD_OK || selection->es_eu ||
|
||||
selection->es_v || selection->es_fu ||
|
||||
!edit->es_int.idb_ptr) {
|
||||
bu_log("nmg\trevert clears selected topology\t%s\tfail\n", unit);
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
|
||||
rt_edit_destroy(edit);
|
||||
db_free_full_path(&path);
|
||||
db_close(dbip);
|
||||
@@ -702,6 +792,7 @@ rt_edit_test_nmg(void)
|
||||
bu_list_len(&wire_loop->down_hd) != edge_count ||
|
||||
!nmg_points_match(ws, wire_expected, NMG_WIRE_VERTEX_COUNT))
|
||||
bu_exit(1, "ERROR: NMG accepted a nonfinite edge split\n");
|
||||
ws->e_inpara = 3;
|
||||
VSCALE(ws->e_para, edge_midpoint, 1.0 / local2base);
|
||||
point_t split_input;
|
||||
VMOVE(split_input, ws->e_para);
|
||||
@@ -765,6 +856,7 @@ rt_edit_test_nmg(void)
|
||||
if (rt_edit_process(ws) == BRLCAD_OK ||
|
||||
!nmg_points_match(ws, wire_expected, NMG_WIRE_VERTEX_COUNT))
|
||||
bu_exit(1, "ERROR: NMG accepted a zero extrusion direction\n");
|
||||
ws->e_inpara = 4;
|
||||
ws->e_para[0] = 0.0; /* dir X */
|
||||
ws->e_para[1] = 0.0; /* dir Y */
|
||||
ws->e_para[2] = 1.0; /* dir Z */
|
||||
@@ -807,6 +899,7 @@ rt_edit_test_nmg(void)
|
||||
!nmg_points_match(ws, wire_and_prism_expected,
|
||||
NMG_WIRE_AND_PRISM_VERTEX_COUNT))
|
||||
bu_exit(1, "ERROR: NMG invalid preview target changed the solid\n");
|
||||
ws->e_inpara = 4;
|
||||
ws->e_para[Z] = 1.0;
|
||||
if (rt_edit_process(ws) != BRLCAD_OK)
|
||||
bu_exit(1, "ERROR: NMG repeated extrusion failed\n");
|
||||
@@ -834,6 +927,7 @@ rt_edit_test_nmg(void)
|
||||
!nmg_points_match(ws, wire_and_prism_expected,
|
||||
NMG_WIRE_AND_PRISM_VERTEX_COUNT))
|
||||
bu_exit(1, "ERROR: NMG accepted a nonfinite extrusion distance\n");
|
||||
ws->e_inpara = 1;
|
||||
ws->e_para[0] = 1.0 / local2base;
|
||||
if (rt_edit_process(ws) != BRLCAD_OK)
|
||||
bu_exit(1, "ERROR: NMG scalar extrusion failed\n");
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#include "bu/log.h"
|
||||
@@ -262,6 +263,56 @@ same_arb_vertices(const struct rt_arb_internal *arb,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
check_atomic_param_rejection(const struct param_case *test,
|
||||
struct rt_db_internal *ip, const struct bn_tol *tol,
|
||||
fastf_t local2base, const char *output)
|
||||
{
|
||||
std::string truncated(output);
|
||||
if (!truncated.empty() && truncated.back() == '\n')
|
||||
truncated.pop_back();
|
||||
size_t last_line = truncated.find_last_of('\n');
|
||||
if (last_line == std::string::npos)
|
||||
return 1;
|
||||
truncated.erase(last_line + 1);
|
||||
|
||||
const std::string invalid[] = {
|
||||
truncated,
|
||||
truncated + "invalid\n",
|
||||
std::string(output) + "unexpected: 1\n"
|
||||
};
|
||||
void *before = bu_malloc(test->parsed_size, "parameter reader snapshot");
|
||||
memcpy(before, test->parsed, test->parsed_size);
|
||||
int failures = 0;
|
||||
for (const std::string &text : invalid) {
|
||||
memcpy(test->parsed, before, test->parsed_size);
|
||||
int result = EDOBJ[test->type].ft_read_params(ip, text.c_str(), tol,
|
||||
local2base);
|
||||
if (result != BRLCAD_ERROR || !test->same(test->parsed, before))
|
||||
failures++;
|
||||
}
|
||||
memcpy(test->parsed, before, test->parsed_size);
|
||||
bu_free(before, "parameter reader snapshot");
|
||||
return failures;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_atomic_reader_type(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case ID_EPA:
|
||||
case ID_EHY:
|
||||
case ID_ETO:
|
||||
case ID_HYP:
|
||||
case ID_RPC:
|
||||
case ID_RHC:
|
||||
case ID_TGC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
run_case(const struct param_case *test, fastf_t local2base, const char *unit)
|
||||
{
|
||||
@@ -296,6 +347,25 @@ run_case(const struct param_case *test, fastf_t local2base, const char *unit)
|
||||
bu_log("%s\tparams\t%s\twrong reconstructed geometry\n", test->name, unit);
|
||||
failed = 1;
|
||||
}
|
||||
if (check_atomic_reader_type(test->type)) {
|
||||
std::string crlf;
|
||||
for (const char *p = output; *p; ++p) {
|
||||
if (*p == '\n')
|
||||
crlf.push_back('\r');
|
||||
crlf.push_back(*p);
|
||||
}
|
||||
if (edit->ft_read_params(&ip, crlf.c_str(), &tol, local2base) != BRLCAD_OK ||
|
||||
!test->same(test->original, test->parsed)) {
|
||||
bu_log("%s\tparams\t%s\tCRLF reconstruction failed\n", test->name, unit);
|
||||
failed = 1;
|
||||
}
|
||||
}
|
||||
if (check_atomic_reader_type(test->type) &&
|
||||
check_atomic_param_rejection(test, &ip, &tol, local2base, output)) {
|
||||
bu_log("%s\tparams\t%s\trejected edit changed geometry\n",
|
||||
test->name, unit);
|
||||
failed = 1;
|
||||
}
|
||||
if (!failed)
|
||||
bu_log("%s\tparams\t%s\tpass\n", test->name, unit);
|
||||
bu_vls_free(&text);
|
||||
|
||||
@@ -1305,6 +1305,17 @@ bu_log("RT_MATRIX_EDIT_TRANS_MODEL_XYZ SUCCESS: "
|
||||
!NEAR_EQUAL(pipe_second(s)->pp_bendradius, 0.5 * inch, SMALL_FASTF))
|
||||
bu_exit(1, "ERROR: inch whole-pipe bend could not be set from zero\n");
|
||||
|
||||
pipe_full_reset(s, pe);
|
||||
if (rt_edit_checkpoint(s) != BRLCAD_OK)
|
||||
bu_exit(1, "ERROR: pipe checkpoint failed\n");
|
||||
pe->es_pipe_pnt = pipe_second(s);
|
||||
pipe_first(s)->pp_coord[X] = inch;
|
||||
VSET(s->e_keypoint, -1, -1, -1);
|
||||
if (rt_edit_revert(s) != BRLCAD_OK || pe->es_pipe_pnt ||
|
||||
!ZERO(pipe_first(s)->pp_coord[X]) ||
|
||||
!VNEAR_ZERO(s->e_keypoint, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: pipe revert retained stale geometry or selection\n");
|
||||
|
||||
int matrix_failures = pipe_transform_matrix(dbip, &fp, &tol, v);
|
||||
matrix_failures += pipe_dimension_matrix(dbip, &fp, &tol);
|
||||
matrix_failures += pipe_point_matrix(dbip, &fp, &tol);
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vmath.h"
|
||||
#include "bu/log.h"
|
||||
#include "bu/malloc.h"
|
||||
@@ -156,6 +159,32 @@ check_rec_units(const fastf_t local2base)
|
||||
!NEAR_EQUAL(MAGNITUDE(rec->b), 2.5 * inch, VUNITIZE_TOL))
|
||||
bu_exit(1, "REC equal-radius edit did not use local units\n");
|
||||
|
||||
const struct rt_tgc_internal saved_rec = *rec;
|
||||
EDOBJ[ID_REC].ft_set_edit_mode(s, ECMD_REC_SET_V);
|
||||
s->e_inpara = 3;
|
||||
VSET(s->e_para, NAN, 0.0, 0.0);
|
||||
if (EDOBJ[ID_REC].ft_edit(s) != BRLCAD_ERROR ||
|
||||
memcmp(rec, &saved_rec, sizeof(saved_rec)))
|
||||
bu_exit(1, "REC accepted an invalid center or changed geometry\n");
|
||||
|
||||
EDOBJ[ID_REC].ft_set_edit_mode(s, ECMD_REC_SET_H);
|
||||
VSET(s->e_para, 0.0, 0.0, tol.dist * 0.5 / local2base);
|
||||
if (EDOBJ[ID_REC].ft_edit(s) != BRLCAD_ERROR ||
|
||||
memcmp(rec, &saved_rec, sizeof(saved_rec)))
|
||||
bu_exit(1, "REC accepted a near-zero height or changed geometry\n");
|
||||
|
||||
const int radius_commands[] = {
|
||||
ECMD_REC_SCALE_R1, ECMD_REC_SCALE_R2, ECMD_REC_SCALE_R
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(radius_commands) / sizeof(radius_commands[0]); i++) {
|
||||
EDOBJ[ID_REC].ft_set_edit_mode(s, radius_commands[i]);
|
||||
s->e_inpara = 1;
|
||||
s->e_para[0] = NAN;
|
||||
if (EDOBJ[ID_REC].ft_edit(s) != BRLCAD_ERROR ||
|
||||
memcmp(rec, &saved_rec, sizeof(saved_rec)))
|
||||
bu_exit(1, "REC accepted an invalid radius or changed geometry\n");
|
||||
}
|
||||
|
||||
s->e_inpara = 1;
|
||||
s->e_para[0] = 0.0;
|
||||
if (EDOBJ[ID_REC].ft_edit(s) != BRLCAD_ERROR ||
|
||||
@@ -175,6 +204,16 @@ check_rec_units(const fastf_t local2base)
|
||||
EDOBJ[ID_REC].ft_edit_get_params(s, ECMD_REC_SCALE_R, NULL) >= 0)
|
||||
bu_exit(1, "REC getter accepted invalid arguments\n");
|
||||
|
||||
point_t saved_center;
|
||||
VMOVE(saved_center, rec->v);
|
||||
if (rt_edit_checkpoint(s) != BRLCAD_OK)
|
||||
bu_exit(1, "REC checkpoint failed\n");
|
||||
rec->v[X] += inch;
|
||||
if (rt_edit_revert(s) != BRLCAD_OK || s->es_int.idb_type != ID_REC ||
|
||||
!VNEAR_EQUAL(((struct rt_tgc_internal *)s->es_int.idb_ptr)->v,
|
||||
saved_center, VUNITIZE_TOL))
|
||||
bu_exit(1, "REC revert lost its type or geometry\n");
|
||||
|
||||
rt_edit_destroy(s);
|
||||
db_free_full_path(&fp);
|
||||
db_close(dbip);
|
||||
|
||||
@@ -420,6 +420,16 @@ rt_edit_test_sph(void)
|
||||
bu_exit(1, "SPH radius command did not restore degenerate axes\n");
|
||||
}
|
||||
|
||||
point_t saved_center;
|
||||
VMOVE(saved_center, ell->v);
|
||||
if (rt_edit_checkpoint(s) != BRLCAD_OK)
|
||||
bu_exit(1, "SPH checkpoint failed\n");
|
||||
ell->v[X] += 1.0;
|
||||
if (rt_edit_revert(s) != BRLCAD_OK || s->es_int.idb_type != ID_SPH ||
|
||||
!VNEAR_EQUAL(((struct rt_ell_internal *)s->es_int.idb_ptr)->v,
|
||||
saved_center, VUNITIZE_TOL))
|
||||
bu_exit(1, "SPH revert lost its type or geometry\n");
|
||||
|
||||
rt_edit_destroy(s);
|
||||
db_close(dbip);
|
||||
return 0;
|
||||
|
||||
@@ -386,6 +386,34 @@ rt_edit_test_tgc(void)
|
||||
bu_exit(1, "ERROR: ECMD_TGC_MV_HH failed\n");
|
||||
bu_log("ECMD_TGC_MV_HH SUCCESS: h=%g,%g,%g\n", V3ARGS(edit_tgc->h));
|
||||
|
||||
const int height_moves[] = {ECMD_TGC_MV_H, ECMD_TGC_MV_HH};
|
||||
for (size_t i = 0; i < sizeof(height_moves) / sizeof(height_moves[0]); i++) {
|
||||
tgc_reset(s, edit_tgc, orig_tgc, cmp_tgc);
|
||||
EDOBJ[dp->d_minor_type].ft_set_edit_mode(s, height_moves[i]);
|
||||
s->local2base = 25.4;
|
||||
s->base2local = 1.0 / s->local2base;
|
||||
s->e_inpara = 3;
|
||||
VSCALE(s->e_para, orig_tgc->v, s->base2local);
|
||||
int result = rt_edit_process(s);
|
||||
if (result != BRLCAD_ERROR ||
|
||||
tgc_diff("rejected zero-height move", cmp_tgc, edit_tgc))
|
||||
bu_exit(1, "ERROR: rejected TGC height move changed geometry (mode %d, result %d, h %g %g %g)\n",
|
||||
height_moves[i], result, V3ARGS(edit_tgc->h));
|
||||
s->local2base = 1.0;
|
||||
s->base2local = 1.0;
|
||||
}
|
||||
|
||||
tgc_reset(s, edit_tgc, orig_tgc, cmp_tgc);
|
||||
EDOBJ[dp->d_minor_type].ft_set_edit_mode(s, ECMD_TGC_MV_H);
|
||||
VMOVE(s->curr_e_axes_pos, orig_tgc->v);
|
||||
point_t rejected_view_target;
|
||||
MAT4X3PNT(rejected_view_target, v->gv_model2view, orig_tgc->v);
|
||||
VMOVE(mousevec, rejected_view_target);
|
||||
if (EDOBJ[dp->d_minor_type].ft_edit_xy(s, mousevec) != BRLCAD_ERROR ||
|
||||
tgc_diff("rejected mouse zero-height move", cmp_tgc, edit_tgc))
|
||||
bu_exit(1, "ERROR: rejected TGC mouse height move changed geometry\n");
|
||||
VADD2(s->curr_e_axes_pos, orig_tgc->v, orig_tgc->h);
|
||||
|
||||
/* ================================================================
|
||||
* ECMD_TGC_ROT_H (rotate H vector by (5,5,5) degrees about keypoint=v)
|
||||
* h_new = R * h where R = bn_mat_angles(5,5,5)
|
||||
|
||||
@@ -240,6 +240,22 @@ rt_edit_test_vol(void)
|
||||
bu_log("RT_PARAMS_EDIT_SCALE SUCCESS: mat[15]=%g (encodes scale=2)\n",
|
||||
edit_vol->mat[15]);
|
||||
|
||||
vol_reset(s, edit_vol);
|
||||
s->e_inpara = 2;
|
||||
s->e_para[0] = 2.0;
|
||||
s->e_para[1] = 3.0;
|
||||
if (rt_edit_process(s) != BRLCAD_ERROR ||
|
||||
!NEAR_EQUAL(edit_vol->mat[15], 1.0, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: rejected generic VOL scale changed geometry or succeeded\n");
|
||||
|
||||
vol_reset(s, edit_vol);
|
||||
s->e_inpara = 1;
|
||||
s->e_para[0] = 0.0;
|
||||
if (rt_edit_process(s) != BRLCAD_ERROR ||
|
||||
!NEAR_EQUAL(edit_vol->mat[15], 1.0, VUNITIZE_TOL) ||
|
||||
!NEAR_EQUAL(s->acc_sc_sol, 1.0, VUNITIZE_TOL))
|
||||
bu_exit(1, "ERROR: rejected zero VOL scale changed edit state\n");
|
||||
|
||||
/* ================================================================
|
||||
* RT_PARAMS_EDIT_TRANS (translate; keypoint (0,0,0) → e_para=(5,5,5))
|
||||
*
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "bu/env.h"
|
||||
#include "bu/log.h"
|
||||
#include "bu/str.h"
|
||||
#include "bu/vls.h"
|
||||
#include "raytrace.h"
|
||||
#include "wdb.h"
|
||||
|
||||
@@ -58,7 +59,7 @@ int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
char line[BUFSIZ];
|
||||
struct bu_vls record = BU_VLS_INIT_ZERO;
|
||||
struct db_i *dbip = NULL;
|
||||
struct rt_wdb *wdbp;
|
||||
struct rt_i *rtip = NULL;
|
||||
@@ -110,10 +111,22 @@ main(int argc, const char **argv)
|
||||
ap.a_hit = shot_hit;
|
||||
ap.a_miss = shot_miss;
|
||||
|
||||
if (rt_rtcmp_capture_set_enabled(1) != -1) failures++;
|
||||
rt_debug = RT_DEBUG_RTCMP;
|
||||
if (shoot(&ap, 0.0) != 1 ||
|
||||
shoot(&ap, primitives ? 5.0 : 2.0) != 0) failures++;
|
||||
if (rt_rtcmp_capture_set_enabled(1) != 0) failures++;
|
||||
if (shoot(&ap, 0.0) != 1 || shoot(&ap, primitives ? 5.0 : 2.0) != 0 ||
|
||||
shoot(&ap, 0.5) != 1) failures++;
|
||||
if (primitives && shoot(&ap, 3.0) != 0) failures++;
|
||||
rt_debug = 0;
|
||||
if (shoot(&ap, 0.0) != 1) failures++;
|
||||
if (rt_rtcmp_capture_set_enabled(0) != 0) failures++;
|
||||
rt_debug = RT_DEBUG_RTCMP;
|
||||
if (shoot(&ap, 0.0) != 1) failures++;
|
||||
if (rt_rtcmp_capture_set_enabled(1) != 0 ||
|
||||
shoot(&ap, 0.5) != 1) failures++;
|
||||
if (rt_rtcmp_capture_set_enabled(0) != 0) failures++;
|
||||
if (rt_rtcmp_capture_flush() != 0) failures++;
|
||||
rt_debug = 0;
|
||||
|
||||
@@ -121,8 +134,10 @@ main(int argc, const char **argv)
|
||||
if (!file) {
|
||||
failures++;
|
||||
} else {
|
||||
if (!bu_fgets(line, sizeof(line), file) || bu_strcmp(line, "{}\n")) failures++;
|
||||
while (bu_fgets(line, sizeof(line), file)) {
|
||||
if (bu_vls_gets(&record, file) < 0 || bu_strcmp(bu_vls_addr(&record), "{}")) failures++;
|
||||
bu_vls_trunc(&record, 0);
|
||||
while (bu_vls_gets(&record, file) >= 0) {
|
||||
const char *line = bu_vls_addr(&record);
|
||||
int is_hit = strstr(line, "\"partitions\":[{") != NULL;
|
||||
int has_segments = strstr(line, "\"segments\":[{") != NULL;
|
||||
if (!strstr(line, "\"ray_dir\":{") ||
|
||||
@@ -134,15 +149,18 @@ main(int argc, const char **argv)
|
||||
(!strstr(line, "\"partitions\":[]") ||
|
||||
!strstr(line, "\"primitive\":\"outer.s\"") ||
|
||||
!strstr(line, "\"primitive\":\"cut.s\"")))) {
|
||||
bu_log("unexpected capture record: %s", line);
|
||||
bu_log("unexpected capture record: %s\n", line);
|
||||
failures++;
|
||||
}
|
||||
if (primitives && !is_hit && has_segments) ++primitive_only;
|
||||
records++;
|
||||
bu_vls_trunc(&record, 0);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
if (records != (primitives ? 4 : 2) || (primitives && primitive_only != 1)) failures++;
|
||||
bu_vls_free(&record);
|
||||
if (records != (primitives ? 5 : 3) ||
|
||||
(primitives && primitive_only != 1)) failures++;
|
||||
|
||||
rt_i_destroy(rtip);
|
||||
db_close(dbip);
|
||||
|
||||
+91
-7
@@ -340,6 +340,26 @@ f_attach(ClientData clientData, Tcl_Interp *interpreter, int argc, const char *a
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_TK
|
||||
static int
|
||||
mged_restore_display_env(Tcl_Interp *interp, Tcl_Obj *saved_display)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (saved_display != NULL) {
|
||||
status = (Tcl_SetVar2Ex(interp, "env", "DISPLAY", saved_display,
|
||||
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) != NULL) ? TCL_OK : TCL_ERROR;
|
||||
Tcl_DecrRefCount(saved_display);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = Tcl_UnsetVar2(interp, "env", "DISPLAY",
|
||||
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
gui_setup(struct mged_state *s, const char *dstr)
|
||||
{
|
||||
@@ -348,6 +368,7 @@ gui_setup(struct mged_state *s, const char *dstr)
|
||||
|
||||
#ifdef HAVE_TK
|
||||
Tk_GenericProc *handler = doEvent;
|
||||
Tcl_Obj *saved_display = NULL;
|
||||
#endif
|
||||
/* initialize only once */
|
||||
if (tkwin != NULL)
|
||||
@@ -355,24 +376,83 @@ gui_setup(struct mged_state *s, const char *dstr)
|
||||
|
||||
Tcl_ResetResult(s->interp);
|
||||
|
||||
/* set DISPLAY to dstr */
|
||||
if (dstr != (char *)NULL) {
|
||||
Tcl_SetVar(s->interp, "env(DISPLAY)", dstr, TCL_GLOBAL_ONLY);
|
||||
#ifdef HAVE_TK
|
||||
/* Tk has no display-name argument in its C initialization API. For an
|
||||
* explicit MGED -d/loadtk argument, env(DISPLAY) is therefore the only
|
||||
* portable way to select an X11 display before Tk_Init. Do not do this
|
||||
* for ambient process state: X11 Tk already reads DISPLAY itself, and
|
||||
* native Win32/Aqua Tk deliberately ignores that X11-only variable. */
|
||||
if (dstr != NULL) {
|
||||
saved_display = Tcl_GetVar2Ex(s->interp, "env", "DISPLAY",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (saved_display != NULL)
|
||||
Tcl_IncrRefCount(saved_display);
|
||||
if (Tcl_SetVar2(s->interp, "env", "DISPLAY", dstr,
|
||||
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
if (saved_display != NULL)
|
||||
Tcl_DecrRefCount(saved_display);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_TK
|
||||
/* This runs the tk.tcl script */
|
||||
if (Tk_Init(s->interp) == TCL_ERROR) {
|
||||
const char *result = Tcl_GetStringResult(s->interp);
|
||||
/* hack to avoid a stupid Tk error */
|
||||
if (bu_strncmp(result, "this isn't a Tk applicationcouldn't", 35) == 0) {
|
||||
result = (result + 27);
|
||||
Tcl_ResetResult(s->interp);
|
||||
Tcl_AppendResult(s->interp, result, (char *)NULL);
|
||||
Tcl_SetObjResult(s->interp, Tcl_NewStringObj(result + 27, -1));
|
||||
}
|
||||
if (dstr != NULL) {
|
||||
Tcl_SavedResult init_result;
|
||||
|
||||
/* Environment restoration is cleanup on this path; retain Tk's
|
||||
* diagnostic even if an unusual Tcl environment trace rejects it. */
|
||||
Tcl_SaveResult(s->interp, &init_result);
|
||||
(void)mged_restore_display_env(s->interp, saved_display);
|
||||
Tcl_RestoreResult(s->interp, &init_result);
|
||||
}
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if (dstr != NULL) {
|
||||
int is_x11;
|
||||
|
||||
if (Tcl_Eval(s->interp, "tk windowingsystem") != TCL_OK) {
|
||||
Tcl_SavedResult windowing_result;
|
||||
|
||||
Tcl_SaveResult(s->interp, &windowing_result);
|
||||
(void)mged_restore_display_env(s->interp, saved_display);
|
||||
Tcl_RestoreResult(s->interp, &windowing_result);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
is_x11 = BU_STR_EQUAL(Tcl_GetStringResult(s->interp), "x11");
|
||||
Tcl_ResetResult(s->interp);
|
||||
|
||||
if (is_x11) {
|
||||
/* X11 may use the explicit display for subsequently created
|
||||
* toplevels and display managers, so keep it in the environment. */
|
||||
if (saved_display != NULL)
|
||||
Tcl_DecrRefCount(saved_display);
|
||||
} else {
|
||||
Tk_Window display_probe;
|
||||
|
||||
/* Win32 and Aqua cannot be redirected by DISPLAY. Restore the
|
||||
* caller's environment, then let Tk validate whether the explicit
|
||||
* name denotes the already initialized native screen. This accepts
|
||||
* native aliases such as :0/:0.0 but reports unsupported alternate
|
||||
* displays instead of silently opening a different screen. */
|
||||
if (mged_restore_display_env(s->interp, saved_display) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
|
||||
display_probe = Tk_CreateWindowFromPath(s->interp,
|
||||
Tk_MainWindow(s->interp), ".__mged_display_probe", dstr);
|
||||
if (display_probe == NULL)
|
||||
return TCL_ERROR;
|
||||
Tk_DestroyWindow(display_probe);
|
||||
Tcl_ResetResult(s->interp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize [incr Tk] */
|
||||
if (Tcl_Eval(s->interp, "package require Itk") != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
@@ -385,6 +465,10 @@ gui_setup(struct mged_state *s, const char *dstr)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_TK
|
||||
(void)dstr;
|
||||
#endif
|
||||
|
||||
/* Initialize the Iwidgets package */
|
||||
if (Tcl_Eval(s->interp, "package require Iwidgets") != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
|
||||
+25
-4
@@ -217,6 +217,16 @@ matrix_scale_edit_flag(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Matrix edits bypass rt_edit_process(), so their callers must synchronize
|
||||
* MGED's cached display matrices and request a redraw. */
|
||||
static void
|
||||
mged_edit_refresh(struct mged_state *s)
|
||||
{
|
||||
new_edit_mats(s);
|
||||
s->update_views = 1;
|
||||
dm_set_dirty(DMP, 1);
|
||||
}
|
||||
|
||||
/* Apply accumulated edit operations using the librt rt_edit APIs */
|
||||
static int
|
||||
mged_librt_knob_edit_apply(struct mged_state *s,
|
||||
@@ -262,11 +272,9 @@ mged_librt_knob_edit_apply(struct mged_state *s,
|
||||
}
|
||||
|
||||
/* Update MGED's cached edit matrices and mark for redraw */
|
||||
new_edit_mats(s);
|
||||
s->update_views = 1;
|
||||
dm_set_dirty(DMP, 1);
|
||||
mged_edit_refresh(s);
|
||||
|
||||
/* Synchronize MGED es_edclass (used by token_should_edit, knob printouts, rate loop) */
|
||||
/* Keep MGED's edit class in sync for knob status and rate handling. */
|
||||
if (did_rot) {
|
||||
s->s_edit->es_edclass = EDIT_CLASS_ROTATE;
|
||||
} else if (did_tran) {
|
||||
@@ -1600,7 +1608,12 @@ f_knob(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
|
||||
}
|
||||
|
||||
if (view_do_tran) {
|
||||
/* Honor the requested view frame even when the active bview is in
|
||||
* object coordinates. */
|
||||
char save_coord = view_state->vs_gvp->gv_coord;
|
||||
view_state->vs_gvp->gv_coord = vcoords;
|
||||
bv_knobs_tran(view_state->vs_gvp, view_tvec, model_mode_final);
|
||||
view_state->vs_gvp->gv_coord = save_coord;
|
||||
}
|
||||
|
||||
if (view_do_rot) {
|
||||
@@ -2477,6 +2490,8 @@ cmd_mrot(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]
|
||||
struct rt_edit *re = MEDIT(s);
|
||||
int matrix_edit = (s->global_editing_state == ST_O_EDIT);
|
||||
rt_knob_edit_rot(re, view_state->vs_gvp->gv_coord, view_state->vs_gvp->gv_rotate_about, matrix_edit, rmat);
|
||||
if (matrix_edit)
|
||||
mged_edit_refresh(s);
|
||||
return TCL_OK;
|
||||
} else {
|
||||
int ret;
|
||||
@@ -2556,6 +2571,8 @@ cmd_rot(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
|
||||
struct rt_edit *re = MEDIT(s);
|
||||
int matrix_edit = (s->global_editing_state == ST_O_EDIT);
|
||||
rt_knob_edit_rot(re, coord, view_state->vs_gvp->gv_rotate_about, matrix_edit, rmat);
|
||||
if (matrix_edit)
|
||||
mged_edit_refresh(s);
|
||||
return TCL_OK;
|
||||
} else {
|
||||
int ret;
|
||||
@@ -2605,6 +2622,8 @@ cmd_arot(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]
|
||||
struct rt_edit *re = MEDIT(s);
|
||||
int matrix_edit = (s->global_editing_state == ST_O_EDIT);
|
||||
rt_knob_edit_rot(re, view_state->vs_gvp->gv_coord, view_state->vs_gvp->gv_rotate_about, matrix_edit, rmat);
|
||||
if (matrix_edit)
|
||||
mged_edit_refresh(s);
|
||||
return TCL_OK;
|
||||
} else {
|
||||
int ret;
|
||||
@@ -2648,6 +2667,8 @@ cmd_tra(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
|
||||
struct rt_edit *re = MEDIT(s);
|
||||
int matrix_edit = (s->global_editing_state == ST_O_EDIT);
|
||||
rt_knob_edit_tran(re, coord, matrix_edit, tvec);
|
||||
if (matrix_edit)
|
||||
mged_edit_refresh(s);
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
|
||||
@@ -273,13 +273,15 @@ common_dm(struct mged_state *s, int argc, const char *argv[])
|
||||
|
||||
if (grid_state->snap) {
|
||||
int save_edflag;
|
||||
int save_edit_mode = RT_EDIT_DEFAULT;
|
||||
|
||||
if ((s->global_editing_state == ST_S_EDIT || s->global_editing_state == ST_O_EDIT) &&
|
||||
mged_variables->mv_transform == 'e') {
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
save_edflag = MEDIT(s)->edit_flag;
|
||||
save_edit_mode = MEDIT(s)->edit_mode;
|
||||
if (!SEDIT_TRAN)
|
||||
MEDIT(s)->edit_flag = RT_PARAMS_EDIT_TRANS;
|
||||
rt_edit_set_edflag(MEDIT(s), RT_PARAMS_EDIT_TRANS);
|
||||
} else {
|
||||
save_edflag = edobj;
|
||||
edobj = BE_O_XY;
|
||||
@@ -287,9 +289,10 @@ common_dm(struct mged_state *s, int argc, const char *argv[])
|
||||
|
||||
snap_keypoint_to_grid(s);
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT)
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
MEDIT(s)->edit_flag = save_edflag;
|
||||
else
|
||||
MEDIT(s)->edit_mode = save_edit_mode;
|
||||
} else
|
||||
edobj = save_edflag;
|
||||
} else
|
||||
snap_view_center_to_grid(s);
|
||||
|
||||
+19
-5
@@ -167,11 +167,24 @@ doEvent(ClientData UNUSED(clientData), void *UNUSED(eventPtr)) {
|
||||
|
||||
|
||||
#ifdef HAVE_X11_TYPES
|
||||
static void
|
||||
eval_motion_command(struct mged_state *s, struct bu_vls *cmd,
|
||||
int save_edflag, int *save_edit_mode)
|
||||
{
|
||||
if (s->global_editing_state == ST_S_EDIT && save_edflag != -1) {
|
||||
*save_edit_mode = MEDIT(s)->edit_mode;
|
||||
if (MEDIT(s)->edit_flag != save_edflag)
|
||||
rt_edit_set_edflag(MEDIT(s), MEDIT(s)->edit_flag);
|
||||
}
|
||||
(void)Tcl_Eval(s->interp, bu_vls_addr(cmd));
|
||||
}
|
||||
|
||||
static void
|
||||
motion_event_handler(struct mged_state *s, XMotionEvent *xmotion)
|
||||
{
|
||||
struct bu_vls cmd = BU_VLS_INIT_ZERO;
|
||||
int save_edflag = -1;
|
||||
int save_edit_mode = RT_EDIT_DEFAULT;
|
||||
fastf_t f;
|
||||
fastf_t fx, fy;
|
||||
fastf_t td;
|
||||
@@ -265,7 +278,7 @@ motion_event_handler(struct mged_state *s, XMotionEvent *xmotion)
|
||||
dy * 0.25, dx * 0.25);
|
||||
}
|
||||
|
||||
(void)Tcl_Eval(s->interp, bu_vls_addr(&cmd));
|
||||
eval_motion_command(s, &cmd, save_edflag, &save_edit_mode);
|
||||
mged_variables->mv_coords = save_coords;
|
||||
|
||||
goto reset_edflag;
|
||||
@@ -339,7 +352,7 @@ motion_event_handler(struct mged_state *s, XMotionEvent *xmotion)
|
||||
}
|
||||
}
|
||||
|
||||
(void)Tcl_Eval(s->interp, bu_vls_addr(&cmd));
|
||||
eval_motion_command(s, &cmd, save_edflag, &save_edit_mode);
|
||||
mged_variables->mv_coords = save_coords;
|
||||
|
||||
goto reset_edflag;
|
||||
@@ -658,13 +671,14 @@ motion_event_handler(struct mged_state *s, XMotionEvent *xmotion)
|
||||
break;
|
||||
}
|
||||
|
||||
(void)Tcl_Eval(s->interp, bu_vls_addr(&cmd));
|
||||
eval_motion_command(s, &cmd, save_edflag, &save_edit_mode);
|
||||
|
||||
reset_edflag:
|
||||
if (save_edflag != -1) {
|
||||
if (s->global_editing_state == ST_S_EDIT)
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
MEDIT(s)->edit_flag = save_edflag;
|
||||
else if (s->global_editing_state == ST_O_EDIT)
|
||||
MEDIT(s)->edit_mode = save_edit_mode;
|
||||
} else if (s->global_editing_state == ST_O_EDIT)
|
||||
edobj = save_edflag;
|
||||
}
|
||||
|
||||
|
||||
+28
-57
@@ -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,13 +733,16 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == BRLCAD_ERROR)
|
||||
return;
|
||||
|
||||
rt_edit_process(MEDIT(s));
|
||||
/* XY rotation's knob path has already processed the edit. */
|
||||
if (MEDIT(s)->edit_flag != RT_PARAMS_EDIT_ROT)
|
||||
rt_edit_process(MEDIT(s));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -773,6 +774,8 @@ objedit_mouse(struct mged_state *s, const vect_t mousevec)
|
||||
rt_edit_set_edflag(MEDIT(s), RT_MATRIX_EDIT_SCALE_Z);
|
||||
break;
|
||||
}
|
||||
} else if (movedir & ROTARROW) {
|
||||
rt_edit_set_edflag(MEDIT(s), RT_MATRIX_EDIT_ROT);
|
||||
} else if (movedir & (RARROW|UARROW)) {
|
||||
int use_x = (movedir & RARROW) ? 1 : 0;
|
||||
int use_y = (movedir & UARROW) ? 1 : 0;
|
||||
@@ -1543,7 +1546,7 @@ f_get_sedit(ClientData clientData, Tcl_Interp *interp, int argc, const char *arg
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if (illump || !illump->s_u_data)
|
||||
if (!illump || !illump->s_u_data)
|
||||
return TCL_ERROR;
|
||||
struct ged_bv_data *bdata = (struct ged_bv_data *)illump->s_u_data;
|
||||
|
||||
@@ -1707,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);
|
||||
|
||||
|
||||
+63
-36
@@ -1436,8 +1436,9 @@ mged_process_char(struct mged_state *s, char ch)
|
||||
int
|
||||
event_check(struct mged_state *s, int non_blocking)
|
||||
{
|
||||
struct mged_dm *save_dm_list;
|
||||
int save_edflag;
|
||||
struct mged_dm *save_dm_list = NULL;
|
||||
int save_edflag = 0;
|
||||
int save_edit_mode = RT_EDIT_DEFAULT;
|
||||
|
||||
if (mged_shutting_down(s))
|
||||
return -1;
|
||||
@@ -1486,8 +1487,9 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
save_edflag = MEDIT(s)->edit_flag;
|
||||
save_edit_mode = MEDIT(s)->edit_mode;
|
||||
if (!SEDIT_ROTATE)
|
||||
MEDIT(s)->edit_flag = RT_PARAMS_EDIT_ROT;
|
||||
rt_edit_set_edflag(MEDIT(s), RT_PARAMS_EDIT_ROT);
|
||||
} else {
|
||||
save_edflag = edobj;
|
||||
edobj = BE_O_ROTATE;
|
||||
@@ -1505,9 +1507,10 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
mged_variables->mv_coords = save_coords;
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT)
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
MEDIT(s)->edit_flag = save_edflag;
|
||||
else
|
||||
MEDIT(s)->edit_mode = save_edit_mode;
|
||||
} else
|
||||
edobj = save_edflag;
|
||||
}
|
||||
if (MEDIT(s)->k.rot_o_flag) {
|
||||
@@ -1520,8 +1523,9 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
save_edflag = MEDIT(s)->edit_flag;
|
||||
save_edit_mode = MEDIT(s)->edit_mode;
|
||||
if (!SEDIT_ROTATE)
|
||||
MEDIT(s)->edit_flag = RT_PARAMS_EDIT_ROT;
|
||||
rt_edit_set_edflag(MEDIT(s), RT_PARAMS_EDIT_ROT);
|
||||
} else {
|
||||
save_edflag = edobj;
|
||||
edobj = BE_O_ROTATE;
|
||||
@@ -1539,9 +1543,10 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
mged_variables->mv_coords = save_coords;
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT)
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
MEDIT(s)->edit_flag = save_edflag;
|
||||
else
|
||||
MEDIT(s)->edit_mode = save_edit_mode;
|
||||
} else
|
||||
edobj = save_edflag;
|
||||
}
|
||||
if (MEDIT(s)->k.rot_v_flag) {
|
||||
@@ -1554,8 +1559,9 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
save_edflag = MEDIT(s)->edit_flag;
|
||||
save_edit_mode = MEDIT(s)->edit_mode;
|
||||
if (!SEDIT_ROTATE)
|
||||
MEDIT(s)->edit_flag = RT_PARAMS_EDIT_ROT;
|
||||
rt_edit_set_edflag(MEDIT(s), RT_PARAMS_EDIT_ROT);
|
||||
} else {
|
||||
save_edflag = edobj;
|
||||
edobj = BE_O_ROTATE;
|
||||
@@ -1573,9 +1579,10 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
mged_variables->mv_coords = save_coords;
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT)
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
MEDIT(s)->edit_flag = save_edflag;
|
||||
else
|
||||
MEDIT(s)->edit_mode = save_edit_mode;
|
||||
} else
|
||||
edobj = save_edflag;
|
||||
}
|
||||
if (MEDIT(s)->k.tra_m_flag) {
|
||||
@@ -1588,8 +1595,9 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
save_edflag = MEDIT(s)->edit_flag;
|
||||
save_edit_mode = MEDIT(s)->edit_mode;
|
||||
if (!SEDIT_TRAN)
|
||||
MEDIT(s)->edit_flag = RT_PARAMS_EDIT_TRANS;
|
||||
rt_edit_set_edflag(MEDIT(s), RT_PARAMS_EDIT_TRANS);
|
||||
} else {
|
||||
save_edflag = edobj;
|
||||
edobj = BE_O_XY;
|
||||
@@ -1606,9 +1614,10 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
mged_variables->mv_coords = save_coords;
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT)
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
MEDIT(s)->edit_flag = save_edflag;
|
||||
else
|
||||
MEDIT(s)->edit_mode = save_edit_mode;
|
||||
} else
|
||||
edobj = save_edflag;
|
||||
}
|
||||
if (MEDIT(s)->k.tra_v_flag) {
|
||||
@@ -1621,8 +1630,9 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
save_edflag = MEDIT(s)->edit_flag;
|
||||
save_edit_mode = MEDIT(s)->edit_mode;
|
||||
if (!SEDIT_TRAN)
|
||||
MEDIT(s)->edit_flag = RT_PARAMS_EDIT_TRANS;
|
||||
rt_edit_set_edflag(MEDIT(s), RT_PARAMS_EDIT_TRANS);
|
||||
} else {
|
||||
save_edflag = edobj;
|
||||
edobj = BE_O_XY;
|
||||
@@ -1639,9 +1649,10 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
mged_variables->mv_coords = save_coords;
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT)
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
MEDIT(s)->edit_flag = save_edflag;
|
||||
else
|
||||
MEDIT(s)->edit_mode = save_edit_mode;
|
||||
} else
|
||||
edobj = save_edflag;
|
||||
}
|
||||
if (MEDIT(s)->k.sca_flag) {
|
||||
@@ -1649,8 +1660,9 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
save_edflag = MEDIT(s)->edit_flag;
|
||||
save_edit_mode = MEDIT(s)->edit_mode;
|
||||
if (!SEDIT_SCALE)
|
||||
MEDIT(s)->edit_flag = RT_PARAMS_EDIT_SCALE;
|
||||
rt_edit_set_edflag(MEDIT(s), RT_PARAMS_EDIT_SCALE);
|
||||
} else {
|
||||
save_edflag = edobj;
|
||||
if (!OEDIT_SCALE)
|
||||
@@ -1663,9 +1675,10 @@ event_check(struct mged_state *s, int non_blocking)
|
||||
Tcl_Eval(s->interp, bu_vls_addr(&vls));
|
||||
bu_vls_free(&vls);
|
||||
|
||||
if (s->global_editing_state == ST_S_EDIT)
|
||||
if (s->global_editing_state == ST_S_EDIT) {
|
||||
MEDIT(s)->edit_flag = save_edflag;
|
||||
else
|
||||
MEDIT(s)->edit_mode = save_edit_mode;
|
||||
} else
|
||||
edobj = save_edflag;
|
||||
}
|
||||
|
||||
@@ -2433,6 +2446,29 @@ apply_cli_overrides(struct mged_state *s, struct mged_cli_overrides *cl)
|
||||
if (cli_dbl_is_set(cl->eye_sep_dist)) CLI_SETVAR_DBL("eye_sep_dist", cl->eye_sep_dist);
|
||||
|
||||
/* --- Tcl mged_default array entries ---------------------------------- */
|
||||
if (cl->dpy_string) {
|
||||
const char *display = cl->dpy_string;
|
||||
#ifdef HAVE_TK
|
||||
struct bu_vls tk_screen = BU_VLS_INIT_ZERO;
|
||||
Tk_Window main_window = Tk_MainWindow(s->interp);
|
||||
|
||||
/* Apply -d after .mgedrc just like the other command-line overrides.
|
||||
* Once Tk is initialized, store its canonical screen name rather than
|
||||
* the spelling used to select it (for example, :0 and :0.0 may denote
|
||||
* the same native screen). Classic/headless mode retains the original
|
||||
* value for a later display-manager attach. */
|
||||
if (main_window != NULL) {
|
||||
bu_vls_printf(&tk_screen, "%s.%d", Tk_DisplayName(main_window),
|
||||
Tk_ScreenNumber(main_window));
|
||||
display = bu_vls_cstr(&tk_screen);
|
||||
}
|
||||
#endif
|
||||
Tcl_SetVar2(s->interp, "mged_default", "display", display,
|
||||
TCL_GLOBAL_ONLY);
|
||||
#ifdef HAVE_TK
|
||||
bu_vls_free(&tk_screen);
|
||||
#endif
|
||||
}
|
||||
if (cl->dm_type)
|
||||
Tcl_SetVar2(s->interp, "mged_default", "dm_type", cl->dm_type, TCL_GLOBAL_ONLY);
|
||||
if (cl->geom)
|
||||
@@ -2681,7 +2717,7 @@ main(int argc, char *argv[])
|
||||
struct bu_opt_desc opt_defs[54];
|
||||
/* ---- Existing short options, now with long aliases ---- */
|
||||
BU_OPT(opt_defs[0], "a", "attach", "type", bu_opt_str, &cl.attach, "display manager attach target");
|
||||
BU_OPT(opt_defs[1], "d", "display", "string", bu_opt_str, &cl.dpy_string, "X display string");
|
||||
BU_OPT(opt_defs[1], "d", "display", "screen", bu_opt_str, &cl.dpy_string, "Tk display and screen name");
|
||||
BU_OPT(opt_defs[2], "r", "read-only", "", NULL, &cl.read_only, "open database read-only");
|
||||
BU_OPT(opt_defs[3], "p", "pipe", "", NULL, &cl.pipe_mode, "pipe mode (emit CMD_DONE sentinels)");
|
||||
BU_OPT(opt_defs[4], "c", "classic", "", NULL, &cl.classic_mode, "classic text-only mode");
|
||||
@@ -3031,9 +3067,6 @@ main(int argc, char *argv[])
|
||||
(void)Tcl_Eval(s->interp, bu_vls_addr(&s->input_str));
|
||||
bu_vls_trunc(&s->input_str, 0);
|
||||
|
||||
if (!s->dpy_string)
|
||||
s->dpy_string = getenv("DISPLAY");
|
||||
|
||||
/* show ourselves */
|
||||
if (s->interactive) {
|
||||
if (s->classic_mged) {
|
||||
@@ -3055,23 +3088,17 @@ main(int argc, char *argv[])
|
||||
/* start up the gui */
|
||||
|
||||
int status;
|
||||
struct bu_vls vls = BU_VLS_INIT_ZERO;
|
||||
struct bu_vls error = BU_VLS_INIT_ZERO;
|
||||
|
||||
(void)Tcl_Eval(s->interp, "set mged_console_mode gui");
|
||||
|
||||
bu_vls_strcpy(&vls, "loadtk");
|
||||
if (s->dpy_string)
|
||||
bu_vls_printf(&vls, " %s", s->dpy_string);
|
||||
|
||||
status = Tcl_Eval(s->interp, bu_vls_addr(&vls));
|
||||
/* An unset -d is deliberately passed as NULL. Tk already knows how
|
||||
* to select its platform display: X11 consults DISPLAY, while the
|
||||
* Win32 and Aqua backends select their native display. Treating an
|
||||
* inherited DISPLAY value as an explicit request breaks native Tk
|
||||
* when Unix-like shells export an X11 placeholder. */
|
||||
status = gui_setup(s, s->dpy_string);
|
||||
bu_vls_strcpy(&error, Tcl_GetStringResult(s->interp));
|
||||
bu_vls_free(&vls);
|
||||
|
||||
if (status != TCL_OK && !s->dpy_string) {
|
||||
/* failed to load tk, try localhost X11 if DISPLAY was not set */
|
||||
status = Tcl_Eval(s->interp, "loadtk :0");
|
||||
}
|
||||
|
||||
if (status != TCL_OK) {
|
||||
if (!run_in_foreground && use_pipe) {
|
||||
|
||||
+4
-2
@@ -513,7 +513,8 @@ f_mouse(
|
||||
return TCL_OK;
|
||||
|
||||
case ST_S_EDIT:
|
||||
if ((SEDIT_TRAN || SEDIT_SCALE || SEDIT_PICK) && mged_variables->mv_transform == 'e')
|
||||
if ((SEDIT_TRAN || SEDIT_SCALE || SEDIT_PICK || SEDIT_ROTATE) &&
|
||||
mged_variables->mv_transform == 'e')
|
||||
sedit_mouse(s, mousevec);
|
||||
else
|
||||
slewview(s, mousevec);
|
||||
@@ -549,7 +550,8 @@ f_mouse(
|
||||
/* case ST_S_VPICK: sedit_vpick(MEDIT(s)); return TCL_OK; */
|
||||
|
||||
case ST_O_EDIT:
|
||||
if ((OEDIT_TRAN || OEDIT_SCALE) && mged_variables->mv_transform == 'e')
|
||||
if ((OEDIT_TRAN || OEDIT_SCALE || OEDIT_ROTATE) &&
|
||||
mged_variables->mv_transform == 'e')
|
||||
objedit_mouse(s, mousevec);
|
||||
else
|
||||
slewview(s, mousevec);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1090,9 +1090,9 @@ namespace delete ::ArcherCoreBootstrap
|
||||
wm withdraw [namespace tail $this]
|
||||
}
|
||||
|
||||
if {![info exists env(DISPLAY)]} {
|
||||
set env(DISPLAY) ":0"
|
||||
}
|
||||
# Tk has already selected its X11, Win32, or Aqua display. DISPLAY is an
|
||||
# X11 input to that initialization, not portable application state; in
|
||||
# particular, synthesizing :0 here can misdirect native Tk child windows.
|
||||
|
||||
set mImgDir [file join [bu_dir data] tclscripts archer images]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -22,12 +22,16 @@ if ![info exists mged_players] {
|
||||
set mged_players {}
|
||||
}
|
||||
|
||||
proc mged_command_busy {options} {
|
||||
expr {[dict exists $options -errorcode] &&
|
||||
[dict get $options -errorcode] eq {BRLCAD MGED COMMAND_BUSY}}
|
||||
}
|
||||
|
||||
proc mged_activate_dm {w} {
|
||||
global tcl_platform
|
||||
|
||||
if {[catch {winset $w} message options]} {
|
||||
if {[dict exists $options -errorcode] &&
|
||||
[dict get $options -errorcode] eq {BRLCAD MGED COMMAND_BUSY}} {
|
||||
if {[mged_command_busy $options]} {
|
||||
return
|
||||
}
|
||||
return -options $options $message
|
||||
@@ -40,6 +44,23 @@ proc mged_activate_dm {w} {
|
||||
}
|
||||
}
|
||||
|
||||
proc mged_release_dm {w} {
|
||||
if {![winfo exists $w]} {
|
||||
return
|
||||
}
|
||||
|
||||
if {[catch {winset $w; dm idle} message options]} {
|
||||
if {[mged_command_busy $options]} {
|
||||
# A mouse pick may pump events while an edit command runs. Defer
|
||||
# the release until its shared GED state is available again.
|
||||
set retry_interval_ms 25
|
||||
after $retry_interval_ms [list mged_release_dm $w]
|
||||
return
|
||||
}
|
||||
return -options $options $message
|
||||
}
|
||||
}
|
||||
|
||||
proc mged_bind_dm { w } {
|
||||
global hot_key
|
||||
global forwarding_key
|
||||
@@ -345,7 +366,7 @@ proc default_mouse_bindings { w } {
|
||||
}
|
||||
}
|
||||
|
||||
bind $w <ButtonRelease> "winset $w; dm idle; break"
|
||||
bind $w <ButtonRelease> "mged_release_dm $w; break"
|
||||
bind $w <Motion> "winset $w; if {\[dm type\] == \"tkswrast\"} {dm motion %x %y}; break"
|
||||
bind $w <KeyRelease-Control_L> "winset $w; dm idle; break"
|
||||
bind $w <KeyRelease-Control_R> "winset $w; dm idle; break"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -25,11 +25,7 @@
|
||||
#
|
||||
|
||||
if ![info exists mged_default(display)] {
|
||||
if [info exists env(DISPLAY)] {
|
||||
set mged_default(display) $env(DISPLAY)
|
||||
} else {
|
||||
set mged_default(display) :0
|
||||
}
|
||||
set mged_default(display) [winfo screen .]
|
||||
}
|
||||
|
||||
if ![info exists mged_gui(mged,screen)] {
|
||||
|
||||
@@ -77,7 +77,7 @@ proc init_solid_edit_menus { stype menu } {
|
||||
set mged_gui($id,transform) e; set_transform $id"
|
||||
incr i
|
||||
.$id.menubar.edit insert $i radiobutton -variable edit_type \
|
||||
-label "None Of Above" -underline 0 -command "set edit_solid_flag 0; \
|
||||
-label "None Of Above" -underline 0 -command "press sedit; \
|
||||
set mged_gui($id,transform) e; set_transform $id"
|
||||
incr i
|
||||
|
||||
|
||||
@@ -24,11 +24,7 @@
|
||||
#
|
||||
|
||||
if ![info exists mged_default(display)] {
|
||||
if [info exists env(DISPLAY)] {
|
||||
set mged_default(display) $env(DISPLAY)
|
||||
} else {
|
||||
set mged_default(display) :0
|
||||
}
|
||||
set mged_default(display) [winfo screen .]
|
||||
}
|
||||
|
||||
if ![info exists mged_gui(mged,screen)] {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+151
-127
@@ -27,10 +27,6 @@ if ![info exists mged_players] {
|
||||
set mged_players {}
|
||||
}
|
||||
|
||||
if ![info exists env(DISPLAY)] {
|
||||
set env(DISPLAY) ":0"
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
# Ensure that tk.tcl has been loaded already via mged command 'loadtk'.
|
||||
#==============================================================================
|
||||
@@ -43,7 +39,6 @@ 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:
|
||||
@@ -519,148 +514,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]
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
|
||||
@@ -154,8 +154,7 @@ proc dump_mged_state {fd} {
|
||||
puts $fd "# Determines the border width in the geometry window"
|
||||
puts $fd "set mged_default(bd) $mged_default(bd)"
|
||||
puts $fd ""
|
||||
puts $fd "# X display string used to determine the screen"
|
||||
puts $fd "# on which to display the GUI's windows"
|
||||
puts $fd "# Tk screen name used for the GUI's windows"
|
||||
puts $fd "set mged_default(display) $mged_default(display)"
|
||||
puts $fd ""
|
||||
puts $fd "# Configures the GUI. Note - this is only"
|
||||
|
||||
@@ -108,13 +108,12 @@ if {![info exists mged_default(config)]} {
|
||||
set mged_default(config) b
|
||||
}
|
||||
|
||||
if {[info exists env(DISPLAY)]} {
|
||||
set mged_default(display) $env(DISPLAY)
|
||||
} else {
|
||||
if {![info exists mged_default(display)]} {
|
||||
set mged_default(display) :0
|
||||
}
|
||||
set env(DISPLAY) $mged_default(display)
|
||||
# DISPLAY is an X11 connection setting, not a portable Tk screen name. Tk is
|
||||
# initialized before this script runs, so its canonical screen is authoritative
|
||||
# on X11, Win32, and Aqua alike. Preserve a value supplied explicitly through
|
||||
# .mgedrc or the gui command for multi-display X11 use.
|
||||
if {![info exists mged_default(display)]} {
|
||||
set mged_default(display) [winfo screen .]
|
||||
}
|
||||
|
||||
if {![info exists mged_default(gdisplay)]} {
|
||||
@@ -2138,9 +2137,6 @@ hoc_register_menu_data "Create" "$ptype..." "Make a $ptype" $ksl
|
||||
|
||||
if { $::tcl_platform(platform) != "windows" && $::tcl_platform(os) != "Darwin" } {
|
||||
bind .$id.t <Enter> "focus .$id.t; break"
|
||||
} else {
|
||||
# some platforms should not be forced window activation
|
||||
focus .$id.t
|
||||
}
|
||||
|
||||
hoc_register_data .$id.t "Command Window"\
|
||||
@@ -2344,6 +2340,13 @@ hoc_register_menu_data "Create" "$ptype..." "Make a $ptype" $ksl
|
||||
if {$comb || $mged_gui($id,show_cmd)} {
|
||||
wm deiconify .$id
|
||||
}
|
||||
|
||||
if {$mged_gui($id,show_cmd) &&
|
||||
($::tcl_platform(platform) == "windows" || $::tcl_platform(os) == "Darwin")} {
|
||||
# These platforms use startup focus instead of the pointer-enter binding.
|
||||
# Wait until the command toplevel is mapped before requesting focus.
|
||||
focus .$id.t
|
||||
}
|
||||
}
|
||||
|
||||
proc cmd_win_hide args {
|
||||
|
||||
Reference in New Issue
Block a user