Commit dd26333d authored by David Thompson's avatar David Thompson Committed by Kitware Robot

Merge topic 'reset-selection-bits'

6f30a6b2 Provide a simple method to reset selection bits.
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: Bob Obara's avatarBob Obara <bob.obara@kitware.com>
Merge-request: !1519
parents 8429bf04 6f30a6b2
Pipeline #134582 running with stage
*.swp
__pycache__
doc/findfigure.pyc
smtk/session/discrete/testing/python/discreteReadFile.pyc
......@@ -13,7 +13,7 @@ set (CTEST_CUSTOM_WARNING_EXCEPTION
# where SMTK directly access symbols from the MOAB library. As of 03/19/2019,
# there is no plan to add symbol exporting to MOAB. Thus, we ignore these
# warnings.
"warning: direct access in function .* to global weak symbol 'typeinfo for moab::.* means the weak symbol cannot be overridden at runtime\. This was likely caused by different translation units being compiled with different visibility settings\."
"warning: direct access in function .* to global weak symbol 'typeinfo for moab::.* means the weak symbol cannot be overridden at runtime\\. This was likely caused by different translation units being compiled with different visibility settings\\."
)
##------------------------------------------------------------------------------
......
## View system changes
### Selections
+ Selections now have a `resetSelectionBits()` method
that provides a way to remove a bit-vector from
all of the objects in the current selection map.
......@@ -16,6 +16,24 @@ import smtk
import smtk.session.discrete
import smtk.testing
"""The following snippet is from PEP 469."""
try:
dict.iteritems
except AttributeError:
# Python 3
def itervalues(d):
return iter(d.values())
def iteritems(d):
return iter(d.items())
else:
# Python 2
def itervalues(d):
return d.itervalues()
def iteritems(d):
return d.iteritems()
def hex2rgb(hexstr):
hh = hexstr[1:] if hexstr[0] == '#' else hexstr
......@@ -163,7 +181,7 @@ class TestDiscreteSplitEdge(smtk.testing.TestCase):
'Edge10': '#0e433b',
'Edge11': '#104c57'
}
for (name, color) in entityColors.iteritems():
for (name, color) in iteritems(entityColors):
self.setEntityProperty(
self.resource.findEntitiesByProperty('name', name),
'color', as_float=hex2rgb(color))
......
......@@ -276,21 +276,25 @@ class TestPolygonCreation(smtk.testing.TestCase):
print('Face {:1} edges {:2}'.format(
ff, ';'.join([x.name() for x in smtk.model.Face(flist[ff]).edges()])))
# Test the easy case: an isolated, non-periodic edge is reshaped:
print('Tweaking {:1} {:2}'.format(edges[0].name(), edges[0].entity()))
print('Tweaking {:1} {:2}'.format(
edges[0].name(), str(edges[0].entity())))
mods = self.tweakEdge(edges[0], [[0, 0], [1, 0], [2, 3], [3, 3]])
tinkered += mods
# Test that when an edge is tweaked whose endpoint is connected to a second edge,
# the second edge's point-sequence and tessellation are also updated:
print('Tweaking {:1} {:2}'.format(edges[1].name(), edges[1].entity()))
print('Tweaking {:1} {:2}'.format(
edges[1].name(), str(edges[1].entity())))
mods = self.tweakEdge(edges[1], [[0, 1], [1, 1]])
tinkered += mods
print('Tweaking {:1} {:2}'.format(edges[4].name(), edges[4].entity()))
print('Tweaking {:1} {:2}'.format(
edges[4].name(), str(edges[4].entity())))
mods = self.tweakEdge(edges[4], [[4, 1.5], [5, 3], [
4.5, 3.25], [4, 3], [4, 1.5]])
tinkered += mods
print('Tweaking {:1} {:2}'.format(edges[3].name(), edges[3].entity()))
print('Tweaking {:1} {:2}'.format(
edges[3].name(), str(edges[3].entity())))
mods = self.tweakEdge(edges[3], [[4, 1.5], [3, 0], [
3.5, -0.25], [4, 0], [4, 1.5]])
tinkered += mods
......
......@@ -134,8 +134,31 @@ class TestCaseMeta(type):
return super(TestCaseMeta, cls).__new__(cls, name, bases, attrs)
class TestCase:
__metaclass__ = TestCaseMeta
def with_metaclass(meta, *bases):
"""Shamelessly stolen from six.
See https://github.com/benjaminp/six for this function's license.
"""
class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
@classmethod
def __prepare__(cls, name, this_bases):
return meta.__prepare__(name, bases)
return type.__new__(metaclass, 'temporary_class', (), {})
class TestCase(with_metaclass(TestCaseMeta)):
"""A base class for SMTK unit tests.
This class extends either vtk.test.Testing.vtkTest (when VTK
is available) or unittest.TestCase (otherwise). If VTK is
available, then image generation and comparison functions
will be available to tests.
"""
def haveVTK(self):
"""Return True if VTK can be imported.
......
......@@ -60,6 +60,7 @@ Selection::Ptr Selection::instance()
Selection::Ptr result;
if (!g_instance)
{
// The following will set g_instance:
result = Selection::create();
}
else
......@@ -133,6 +134,33 @@ int Selection::findOrCreateLabeledValue(const std::string& label)
return it->second;
}
bool Selection::resetSelectionBits(const std::string& source, int value)
{
bool modified = false;
int mask = ~value;
for (auto it = m_selection.begin(); it != m_selection.end(); /* fancy */)
{
auto curr = it;
bool shouldErase = (it->second & mask) == 0;
modified |= (it->second & value) != 0;
it->second = it->second & mask;
++it;
if (shouldErase)
{
m_selection.erase(curr);
}
}
if (modified)
{
this->observers()(source, shared_from_this());
}
return modified;
}
bool Selection::setDefaultAction(const SelectionAction& action)
{
switch (action)
......
......@@ -277,6 +277,15 @@ public:
bool modifySelection(const T& objects, const std::string& source, int value,
SelectionAction action = SelectionAction::DEFAULT, bool bitwise = false);
/**\brief Reset values in the selection map so no entries contain the given bit \a value.
*
* This method assumes each value in the selection map is a bit vector.
*
* This will remove objects from the selection entirely if their
* selection value is a subset of the bits set in \a value.
*/
bool resetSelectionBits(const std::string& source, int value);
/**\brief Default selection action.
*
* Some applications need to separate the choice of which SelectionAction
......
......@@ -67,8 +67,8 @@ PySharedPtrClass< smtk::view::Selection > pybind11_init_smtk_view_Selection(py::
(smtk::view::Selection::*)(const ::std::vector<smtk::resource::PersistentObject::Ptr>&,
const std::string&, int, smtk::view::SelectionAction, bool))
&smtk::view::Selection::modifySelection)
.def("resetSelectionBits", &smtk::view::Selection::resetSelectionBits)
.def("visitSelection", (void (smtk::view::Selection::*)(::std::function<void (std::shared_ptr<smtk::resource::PersistentObject>, int)>)) &smtk::view::Selection::visitSelection, py::arg("visitor"))
.def("visitSelection", (void (smtk::view::Selection::*)(::std::function<void (std::shared_ptr<smtk::resource::Component>, int)>)) &smtk::view::Selection::visitSelection, py::arg("visitor"))
.def("setFilter", &smtk::view::Selection::setFilter, py::arg("fn"), py::arg("refilterSelection") = true)
.def("currentSelection", (smtk::view::Selection::SelectionMap & (smtk::view::Selection::*)(::smtk::view::Selection::SelectionMap &) const) &smtk::view::Selection::currentSelection, py::arg("selection"))
.def("currentSelection", (smtk::view::Selection::SelectionMap const & (smtk::view::Selection::*)() const) &smtk::view::Selection::currentSelection)
......
......@@ -18,7 +18,10 @@ import smtk.view
import sys
import uuid
from copy import copy
eventCount = 0
eventCount2 = 0
class TestSelection(smtk.testing.TestCase):
......@@ -26,6 +29,9 @@ class TestSelection(smtk.testing.TestCase):
def setUp(self):
self.selnMgr = smtk.view.Selection.create()
def tearDown(self):
self.selnMgr = None
def loadTestData(self):
import os
self.mgr = smtk.model.Resource.create()
......@@ -122,8 +128,8 @@ class TestSelection(smtk.testing.TestCase):
# Test that observer is called at proper times:
handle = mgr.observers().insert(observer, 0, True)
self.assertGreaterEqual(
handle, 0, 'Failed to register selection observer.')
self.assertTrue(
handle.assigned(), 'Failed to register selection observer.')
expectedEventCount = 1
self.assertEqual(eventCount, expectedEventCount,
'Selection observer was not called immediately.')
......@@ -225,6 +231,84 @@ class TestSelection(smtk.testing.TestCase):
self.assertEqual(
visitSeln, ddExpected, 'Did not visit selection properly.')
def testBitwiseOperations(self):
self.loadTestData()
mgr = self.selnMgr
def observer(src, smgr):
global eventCount2
eventCount2 += 1
# Test that observer is called at proper times:
handle = mgr.observers().insert(observer, 0, True)
self.assertTrue(
handle.assigned(), 'Failed to register selection observer.')
expectedEventCount = 1
comp = self.resource.find(self.model.entity())
model = smtk.model.Model(comp.modelResource(), comp.id())
cellComps = [self.resource.find(cell.entity())
for cell in model.cells()]
lots = copy(cellComps)
selnVal = mgr.findOrCreateLabeledValue('selection')
selnVal2 = mgr.findOrCreateLabeledValue('selection2')
selnSrc = 'testSelectionModificationObserve'
mgr.registerSelectionSource(selnSrc)
mgr.registerSelectionValue('selection', selnVal)
mgr.registerSelectionValue('selection2', selnVal2)
print('Selection values: %d %d' % (selnVal, selnVal2))
# Test selection modification and ensure observer is called properly:
mgr.modifySelection(
lots, selnSrc, selnVal, smtk.view.SelectionAction.DEFAULT, False)
expectedEventCount += 1
# Add the model to the list of entities so each selection bit
# has >= 1 component with *only* that bit present.
lots.append(comp)
mgr.modifySelection(
lots[8:], selnSrc, selnVal2, smtk.view.SelectionAction.FILTERED_ADD, True)
expectedEventCount += 1
print('Before: %d items in selection (%d cells)' %
(len(mgr.currentSelection()), len(cellComps)))
self.assertEqual(eventCount2, expectedEventCount,
'Selection observer was not called.')
self.assertEqual(len(mgr.currentSelection()), 17,
'Expected 16 cells + 1 model in selection.')
# Remove the selnVal2 bit (this should remove comp from the selection)
mgr.resetSelectionBits(selnSrc, selnVal2)
expectedEventCount += 1
print('After1: %d items in selection' % len(mgr.currentSelection()))
self.assertEqual(len(mgr.currentSelection()), 16,
'Expected 16 cells in selection at this point.')
self.assertEqual(eventCount2, expectedEventCount,
'Selection observer was not called upon modification.')
# Remove the selnVal2 bit again (resulting in no changes)
mgr.resetSelectionBits(selnSrc, selnVal2)
print('After2: %d items in selection' % len(mgr.currentSelection()))
self.assertEqual(len(mgr.currentSelection()), 16,
'Expected 16 cells in selection at this point.')
self.assertEqual(eventCount2, expectedEventCount,
'Selection observer was not called upon modification.')
# Remove the selnVal bit (this should remove lots[8:] from the
# selection)
mgr.resetSelectionBits(selnSrc, selnVal)
expectedEventCount += 1
print('After3: %d items in selection' % len(mgr.currentSelection()))
self.assertEqual(eventCount2, expectedEventCount,
'Selection observer was not called upon modification.')
self.assertEqual(len(mgr.currentSelection()), 0,
'Expected 0 cells in selection at this point.')
print('')
if __name__ == '__main__':
smtk.testing.process_arguments()
smtk.testing.main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment