A very simple face area sniffer tool example per request by Braden York.
NOTE: Updated version in next post with extra features.
Examples_FaceSniffer_1.0.0.rbz (1.7 KB)
The extension registrar script for the "Plugins" folder:
# encoding: UTF-8
# File: Plugins/Examples_FaceSniffer.rb
#
# An example that adds an "FaceSniffer" tool item to the bottom of the
# "Tools" menu.
#
# Copyright 2022, released under the MIT License
#
# * v 1.0.0 - Dan Rathbun
#
# Permission to use, copy, modify, and distribute this software for any purpose
# and without fee is hereby granted, provided that the above copyright notice
# appear in all copies.
#
# However if you modify it, PLEASE change the top level namespace module name
# in both files to YOUR OWN unique top level namespace module, and then add
# your copyright notice to the list above.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
#-----------------------------------------------------------------------------
module Examples
module FaceSniffer
EXTENSION = SketchupExtension.new(
'Face Sniffer',
'Examples_FaceSniffer/FaceSniffer_main.rb'
)
EXTENSION.instance_eval {
self.description= 'Adds a Tools > Face Sniffer command.'
self.version= '1.0.0'
self.copyright= "©2022 under MIT License"
self.creator= 'Dan Rathbun'
}
Sketchup.register_extension(EXTENSION, true)
end # extension submodule
end # top level namespace module
And the main file in the "Examples_FaceSniffer" folder:
# encoding: UTF-8
# This is the main file that implements the sniffer tool.
#
# If you modify this example extension, you should change the
# top level namespace module name to your unique namespace.
# Also then add your copyright notice to the comments at the
# top of the extension registrar file.
module Examples # <-- the top level namespace module
module FaceSniffer # extension submodule
class FaceSnifferTool
CURSOR ||= UI.create_cursor(
Sketchup.find_support_file('cursor_select.svg', 'Images'),
0, 0
)
def initialize
@selset = Sketchup.active_model.selection
end
def activate
Sketchup.set_status_text(
'Select faces to see their area in Entity Info'
)
end
def deactivate(view)
@selset.clear
Sketchup.set_status_text("")
end
def onSetCursor
UI.set_cursor(CURSOR)
end
def onLButtonUp(flags, x, y, view)
ph = view.pick_helper
num = ph.do_pick(x,y)
if num > 0
@selset.clear
@selset.add(ph.picked_face)
end
end
def self.activate
Sketchup.active_model.select_tool(self.new)
end
end # tool class
if !defined?(@loaded)
@loaded = true
CMD = UI::Command.new('Face Sniffer') {
FaceSnifferTool.activate
}
CMD.status_bar_text = "Pick Nested Faces to see Area"
UI.menu('Tools').add_item(CMD)
end
end # extension submodule
end # namespace module
~
5 Likes
A little more complex edition of the same extension.
Examples_FaceSniffer_2.0.0.rbz (2.7 KB)
- Still will select nested faces
- Display correct cumulative area for scaled faces in the VCB
(Ignore the area in Model Info as it will be incorrect for scaled faces.)
- Displays area in correct model units format
- Reacts to changes in units area format instantly
- Mimics native Select Tool for adding, removing, toggling to selection
- Uses native select cursors
- ESC key will now reset tool
The extension registrar script for the "Plugins" folder:
# encoding: UTF-8
# File: Plugins/Examples_FaceSniffer.rb
#
# An example that adds an "FaceSniffer" tool item to the bottom of the
# "Tools" menu. This tool shows the cumulative area of selected faces
# in the Value Control Box. It allows picking nested faces.
#
# Copyright 2022, released under the MIT License
#
# * v 2.0.0 - Dan Rathbun
#
# Permission to use, copy, modify, and distribute this software for any purpose
# and without fee is hereby granted, provided that the above copyright notice
# appear in all copies.
#
# However if you modify it, PLEASE change the top level namespace module name
# in both files to YOUR OWN unique top level namespace module, and then add
# your copyright notice to the list above.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
#-----------------------------------------------------------------------------
module Examples
module FaceSniffer
EXTENSION = SketchupExtension.new(
'Face Aera Sniffer',
'Examples_FaceSniffer/FaceSniffer_main.rb'
)
EXTENSION.instance_eval {
self.description= 'Adds a Tools > Face Area Sniffer command.'
self.version= '2.0.0'
self.copyright= "©2022 under MIT License"
self.creator= 'Dan Rathbun'
}
Sketchup.register_extension(EXTENSION, true)
end # extension submodule
end # top level namespace module
And the main file in the "Examples_FaceSniffer" folder:
# encoding: UTF-8
# This is the main file that implements the sniffer tool.
#
# If you modify this example extension, you should change the
# top level namespace module name to your unique namespace.
# Also then add your copyright notice to the comments at the
# top of the extension registrar file.
module Examples # <-- the top level namespace module
module FaceSniffer # extension submodule
class FaceSnifferTool
#{# CONSTANTS : Native Cursor IDs
#
IDC_SELECT_ONE ||= 633 # Select one
IDC_SELECT_ADD ||= 634 # Select +
IDC_SELECT_REM ||= 636 # Select -
IDC_SELECT_TOG ||= 635 # Select +/-
#
#}#
def initialize
@area = 0
@model = Sketchup.active_model
@model.options['UnitsOptions'].add_observer(self)
@selset = @model.selection
end
def activate
reset()
update_area()
end
def clear_ui
Sketchup.set_status_text("")
Sketchup.set_status_text('', SB_VCB_LABEL)
Sketchup.set_status_text('', SB_VCB_VALUE)
end
def deactivate(view)
@selset.clear
clear_ui()
@model.options['UnitsOptions'].remove_observer(self)
end
def onCancel(reason, view)
if reason == 0
@selset.clear
@area = 0
reset()
end
end
def onKeyDown(key, repeat, flags, view)
# Set the tool's cursor ID appropriately for the select mode:
if key == VK_SHIFT
@shift = true
if @ctrl
#puts "SHIFT now pressed + CTRL"
@cursor = IDC_SELECT_REM # remove
else
#puts "SHIFT is pressed"
@cursor = IDC_SELECT_TOG # toggle
end
onSetCursor()
elsif key == VK_CONTROL # add
@ctrl = true
if @shift
#puts "CTRL now pressed + SHIFT"
@cursor = IDC_SELECT_REM # remove
else
#puts "CTRL is pressed"
@cursor = IDC_SELECT_ADD # add
end
onSetCursor()
end
false
end
def onKeyUp(key, repeat, flags, view)
# Set the tool's cursor ID appropriately for the select mode:
if key == VK_SHIFT
@shift = false
if @ctrl # was remove mode
#puts "SHIFT released, CTRL is pressed"
@cursor = IDC_SELECT_ADD # add
else # was toggle mode
#puts "SHIFT was released"
@cursor = IDC_SELECT_ONE # normal
end
onSetCursor()
elsif key == VK_CONTROL
@ctrl = false
if @shift # was remove mode
#puts "CTRL released, SHIFT is pressed"
@cursor = IDC_SELECT_TOG # toggle
else # was add mode
#puts "CTRL was released"
@cursor = IDC_SELECT_ONE # normal
end
onSetCursor()
end
# otherwise do nothing
end
def onLButtonUp(flags, x, y, view)
ph = view.pick_helper
num = ph.do_pick(x,y)
#puts "items picked = #{num}"
return unless num > 0
face = ph.picked_face
index = ph.count.times.find { |i| ph.leaf_at(i) == face }
trans = index ? ph.transformation_at(index) : IDENTITY
area = face.area(trans)
# Note: Selection #add, #remove, and #toggle are method aliases.
if pressed_shift_and_control(flags) # remove
#puts "SHIFT + CTRL is pressed"
if @selset.contains?(face)
@selset.remove(face)
@area -= area
end
elsif pressed_shift(flags) # toggle
#puts "SHIFT is pressed"
@selset.contains?(face) ? @area -= area : @area += area
@selset.toggle(face)
elsif pressed_control(flags) # add
#puts "CTRL is pressed"
unless @selset.contains?(face)
@selset.add(face)
@area += area
end
else # clear and add
#puts "No modifiers pressed"
@selset.clear
@selset.add(face)
@area = area
end
update_area()
end
def onSetCursor
UI.set_cursor(@cursor)
end
def pressed_control(flags)
(flags & COPY_MODIFIER_MASK) == COPY_MODIFIER_MASK
end
def pressed_shift(flags)
(flags & CONSTRAIN_MODIFIER_MASK) == CONSTRAIN_MODIFIER_MASK
end
def pressed_shift_and_control(flags)
pressed_shift(flags) && pressed_control(flags)
end
def reset(view = Sketchup.active_model.active_view)
@cursor = IDC_SELECT_ONE
@shift = false
@ctrl = false
Sketchup.set_status_text('Select faces to see their area in VCB')
Sketchup.set_status_text('Area:', SB_VCB_LABEL)
update_area()
view.invalidate
end
def resume(view)
reset()
end
def suspend(view)
clear_ui()
end
def update_area
Sketchup.set_status_text(Sketchup.format_area(@area), SB_VCB_VALUE)
end
### OBSERVER CALLBACK
def onOptionsProviderChanged(provider, name)
update_area()
end
### CLASS METHODS
def self.activate
Sketchup.active_model.select_tool(self.new)
end
end # tool class
if !defined?(@loaded)
@loaded = true
CMD = UI::Command.new('Face Area Sniffer') { FaceSnifferTool.activate }
CMD.status_bar_text = "Pick Nested Faces to see Area"
UI.menu('Tools').add_item(CMD)
end
end # extension submodule
end # namespace module
3 Likes