Commit 3c5c1521 authored by David Thompson's avatar David Thompson Committed by Kitware Robot

Merge topic 'oscillator-example'

2ed0955b Add an example session and fix several issues.
ccdb4a21 Selection icons: use gray instead of black
894d68ac Standardize the install location for configuration files
1e74993c Update release instructions to better define
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: T.J. Corona's avatarT.J. Corona <tj.corona@kitware.com>
Merge-request: !1408
parents f7d0f21a 2ed0955b
......@@ -146,6 +146,7 @@ if (SMTK_ENABLE_MULTISCALE_SESSION)
set(AFRL_DIR "/path/to/afrl/data" CACHE PATH "Path to a directory of AFRL data.")
endif()
option(SMTK_ENABLE_RGG_SESSION "Build RGG reactor model session." ON)
option(SMTK_ENABLE_OSCILLATOR_SESSION "Build example oscillator model session." ON)
# SMTK_BUILD_DOCUMENTATION is an enumerated option:
# never == No documentation, and no documentation tools are required.
......
......@@ -339,7 +339,7 @@ T Attribute::associatedObjects() const
for (auto it = m_associatedObjects->begin(); it != m_associatedObjects->end(); ++it)
{
auto entry = std::dynamic_pointer_cast<typename T::value_type>(*it);
auto entry = std::dynamic_pointer_cast<typename T::value_type::element_type>(*it);
if (entry)
{
result.insert(result.end(), entry);
......
......@@ -935,7 +935,11 @@ std::set<AttributePtr> Resource::attributes(
const_cast<Resource*>(this)->shared_from_this(), Resource::AssociationRole);
for (auto obj : objs)
{
result.insert(std::dynamic_pointer_cast<Attribute>(obj));
auto entry = std::dynamic_pointer_cast<Attribute>(obj);
if (entry)
{ // Never insert a failed dynamic cast (null pointer)
result.insert(entry);
}
}
return result;
}
......@@ -28,8 +28,6 @@
#include "pqApplicationCore.h"
#include "pqObjectBuilder.h"
vtkSMProxy* pqSMTKAppComponentsAutoStart::s_resourceManager = nullptr;
pqSMTKAppComponentsAutoStart::pqSMTKAppComponentsAutoStart(QObject* parent)
: Superclass(parent)
{
......
......@@ -32,7 +32,6 @@ public:
void shutdown();
protected:
static vtkSMProxy* s_resourceManager;
pqPluginSMTKViewBehavior* m_viewTracker;
private:
......
......@@ -96,8 +96,7 @@ void pqCloseResourceReaction::closeResource()
if (ret == QMessageBox::Save)
{
pqActiveObjects* activeObjects = &pqActiveObjects::instance();
activeObjects->setActiveSource(smtkResource);
activeObjects.setActiveSource(smtkResource);
pqSaveResourceReaction::State state = pqSaveResourceReaction::saveResource();
if (state == pqSaveResourceReaction::State::Aborted)
{
......
......@@ -24,6 +24,7 @@
// Client side
#include "pqActiveObjects.h"
#include "pqLiveInsituManager.h"
#include "pqPipelineSource.h"
#include "pqSelectionManager.h"
#include "pqServerManagerModel.h"
......@@ -37,6 +38,7 @@ static pqSMTKPipelineSelectionBehavior* g_pipelineSelection = nullptr;
pqSMTKPipelineSelectionBehavior::pqSMTKPipelineSelectionBehavior(QObject* parent)
: Superclass(parent)
, m_changingSource(false)
, m_selectionValue("selected")
{
if (!g_pipelineSelection)
......@@ -165,8 +167,19 @@ void pqSMTKPipelineSelectionBehavior::onActiveSourceChanged(pqPipelineSource* so
m_changingSource = true;
auto behavior = pqSMTKBehavior::instance();
behavior->visitResourceManagersOnServers(
[this, &activeResources](pqSMTKWrapper* wrapper, pqServer*) -> bool {
[this, &activeResources](pqSMTKWrapper* wrapper, pqServer* server) -> bool {
// skip bad servers
if (!wrapper || pqLiveInsituManager::isInsituServer(server))
{
return false;
}
auto seln = wrapper->smtkSelection();
if (!seln)
{
return false;
}
int value = seln->selectionValueFromLabel(m_selectionValue);
seln->modifySelection(activeResources, "pqSMTKPipelineSelectionBehavior", value,
smtk::view::SelectionAction::UNFILTERED_REPLACE, true);
......
......@@ -45,7 +45,7 @@
template <typename T, typename U>
int UpdateVisibilityForFootprint(pqSMTKModelRepresentation* smap, const T& comp, int visible,
U& visibleThings, const smtk::view::DescriptivePhrasePtr& phr)
U& visibleThings, const smtk::view::DescriptivePhrasePtr&)
{
bool didUpdate = false;
int rval;
......
......@@ -47,7 +47,7 @@ pqSMTKSaveOnCloseResourceBehavior::pqSMTKSaveOnCloseResourceBehavior(QObject* pa
{
// Wait until the event loop starts, ensuring that the main window will be
// accessible.
QTimer::singleShot(0, this, [this]() {
QTimer::singleShot(0, this, []() {
// Blech: pqApplicationCore doesn't have the selection manager yet,
// so wait until we hear that the server is ready to make the connection.
// We can't have a selection before the first connection, anyway.
......
......@@ -31,6 +31,7 @@
// Client side
#include "pqApplicationCore.h"
#include "pqLiveInsituManager.h"
#include "pqOutputPort.h"
#include "pqPVApplicationCore.h"
#include "pqSelectionManager.h"
......@@ -193,6 +194,12 @@ void pqSMTKSelectionFilterBehavior::filterSelectionOnServer(
std::cout << " filterSelectionOnServer: no mgr\n";
return;
}
if (pqLiveInsituManager::isInsituServer(server) ||
pqLiveInsituManager::instance()->isDisplayServer(server))
{
std::cout << " server is catalyst connection... ignoring.\n";
return;
}
//auto seln = mgr->GetSelection();
auto seln = vtkSMTKWrapper::SafeDownCast(mgr->GetClientSideObject())
->GetSelection(); // TODO: Only works on built-in server
......
......@@ -67,6 +67,7 @@ qtItem* qtReferenceItem::createItemWidget(const AttributeItemInfo& info)
qtReferenceItemData::qtReferenceItemData()
: m_optional(nullptr)
, m_alreadyClosingPopup(false)
, m_modelObserverId(-1)
{
}
......@@ -211,7 +212,12 @@ void qtReferenceItem::synchronizeAndHide(bool escaping)
QString qsyn = QString::fromStdString(syn);
updateLabel(m_p->m_synopsis, qsyn, ok);
m_p->m_editBtn->menu()->hide();
if (!m_p->m_alreadyClosingPopup)
{
m_p->m_alreadyClosingPopup = true;
m_p->m_editBtn->menu()->hide();
m_p->m_alreadyClosingPopup = false;
}
}
void qtReferenceItem::copyFromSelection()
......@@ -503,6 +509,7 @@ void qtReferenceItem::updateUI()
m_p->m_editBtn->menu()->addAction(action);
m_p->m_editBtn->setMaximumSize(QSize(16, 20));
QObject::connect(m_p->m_editBtn->menu(), SIGNAL(aboutToHide()), this, SLOT(popupClosing()));
QObject::connect(m_p->m_qtDelegate, SIGNAL(requestVisibilityChange(const QModelIndex&)),
m_p->m_qtModel, SLOT(toggleVisibility(const QModelIndex&)));
......@@ -523,6 +530,16 @@ void qtReferenceItem::updateUI()
this->updateSynopsisLabels();
}
void qtReferenceItem::popupClosing()
{
if (!m_p->m_alreadyClosingPopup)
{
m_p->m_alreadyClosingPopup = true;
this->synchronizeAndHide(false);
m_p->m_alreadyClosingPopup = false;
}
}
std::string qtReferenceItem::synopsis(bool& ok) const
{
auto item = m_itemInfo.itemAs<smtk::attribute::ReferenceItem>();
......@@ -668,9 +685,12 @@ bool qtReferenceItem::eventFilter(QObject* src, QEvent* event)
break;
case QEvent::Hide:
{
// The user has clicked outside the popup.
// Decide whether to update the item state or abandon.
this->synchronizeAndHide(false);
if (m_p->m_popup->isVisible())
{
// The user has clicked outside the popup.
// Decide whether to update the item state or abandon.
this->synchronizeAndHide(false);
}
}
break;
default:
......@@ -771,6 +791,13 @@ void qtReferenceItem::checkRemovedComponents(smtk::view::DescriptivePhrasePtr ph
{
bool didChange = false;
auto itm = this->itemAs<smtk::attribute::ReferenceItem>();
// If the application releases its hold on the attribute
// resource being represented, then we may not have an item:
if (!itm)
{
return;
}
auto qidx = m_p->m_qtModel->indexFromPath(src);
for (auto ref : refs)
{
......
......@@ -55,6 +55,15 @@ protected slots:
virtual void selectionLinkToggled(bool linked);
virtual void setOutputOptional(int state);
/**\brief Called whenever the edit button's QMenu is about to hide.
*
* This may or may not be initiated by synchronizeAndHide().
* If not, then it is initiated directly by the user clicking outside
* the popup, so it will call synchronizeAndHide() with
* m_p->m_alreadyClosingPopup set so that it will only synchronize and
* not hide.
*/
void popupClosing();
/**\brief Link this item to the "hovered" selection bit.
*
* This should set up the initial state, observe changes to the item, and update
......
......@@ -72,6 +72,7 @@ public:
QDialog* m_popup;
QVBoxLayout* m_popupLayout;
QListView* m_popupList;
bool m_alreadyClosingPopup; // Set when synchronizeAndHide() should **not** hide the QMenu.
// Selection state of items shown in m_phraseModel:
std::map<smtk::resource::PersistentObjectPtr, int> m_members;
......
......@@ -272,9 +272,22 @@ void vtkAuxiliaryGeometryExtension::addCacheGeometry(const vtkSmartPointer<vtkDa
vtkSmartPointer<vtkDataObject> vtkAuxiliaryGeometryExtension::fetchCachedGeometry(
const smtk::model::AuxiliaryGeometry& entity)
{
std::time_t dummy;
return vtkAuxiliaryGeometryExtension::fetchCachedGeometry(entity, dummy);
}
vtkSmartPointer<vtkDataObject> vtkAuxiliaryGeometryExtension::fetchCachedGeometry(
const smtk::model::AuxiliaryGeometry& entity, std::time_t& cachedTime)
{
vtkAuxiliaryGeometryExtension::ensureCache();
return std::get<ClassInternal::DATA>(s_p->fetch(entity));
auto entry = s_p->fetch(entity);
auto result = std::get<ClassInternal::DATA>(entry);
if (result)
{
cachedTime = std::get<ClassInternal::TIMESTAMP>(entry);
}
return result;
}
double vtkAuxiliaryGeometryExtension::currentCacheSize()
......
......@@ -59,9 +59,16 @@ public:
static void addCacheGeometry(const vtkSmartPointer<vtkDataObject> dataset,
const smtk::model::AuxiliaryGeometry& entity, std::time_t& mtime, bool trimCache);
/// Return VTK data created by a previous call to canHandleAuxiliaryGeometry.
/**\brief Return VTK data created by a previous call to canHandleAuxiliaryGeometry.
*
* The variant that accepts a reference to std::time_t will return the
* timestamp provided when addCacheGeometry() was called (if a cache entry
* is found; if no entry for \a entity is found, then its value is unmodified).
*/
static vtkSmartPointer<vtkDataObject> fetchCachedGeometry(
const smtk::model::AuxiliaryGeometry& entity);
static vtkSmartPointer<vtkDataObject> fetchCachedGeometry(
const smtk::model::AuxiliaryGeometry& entity, std::time_t& cachedTime);
/// Return the size (in kiB) of the current geometry cache.
static double currentCacheSize();
......
......@@ -402,13 +402,19 @@ vtkSmartPointer<vtkDataObject> vtkModelMultiBlockSource::GenerateRepresentationF
}
if (bShow)
{
auto ext = vtkAuxiliaryGeometryExtension::create();
std::vector<double> bbox;
if (ext->canHandleAuxiliaryGeometry(aux, bbox))
{
auto cgeom = ext->fetchCachedGeometry(aux);
return cgeom;
}
vtkSmartPointer<vtkDataObject> cgeom;
smtk::common::Extension::visit<vtkAuxiliaryGeometryExtension::Ptr>(
[&cgeom, &aux](
const std::string&, vtkAuxiliaryGeometryExtension::Ptr ext) -> std::pair<bool, bool> {
std::vector<double> bbox;
if (ext->canHandleAuxiliaryGeometry(aux, bbox))
{
cgeom = ext->fetchCachedGeometry(aux);
return std::make_pair(true, true);
}
return std::make_pair(false, false);
});
return cgeom;
}
}
return vtkSmartPointer<vtkDataObject>();
......
......@@ -7,6 +7,7 @@ set(SMTK_MESH_SESSION_ENABLED "False")
set(SMTK_MULTISCALE_SESSION_ENABLED "False")
set(SMTK_RGG_SESSION_ENABLED "False")
set(SMTK_VTK_SESSION_ENABLED "False")
set(SMTK_OSCILLATOR_SESSION_ENABLED "False")
################################################################################
# Build Discrete session
......@@ -56,6 +57,14 @@ if (SMTK_ENABLE_VTK_SESSION)
add_subdirectory(vtk)
endif()
################################################################################
# Build Oscillator session
################################################################################
if (SMTK_ENABLE_OSCILLATOR_SESSION)
set(SMTK_OSCILLATOR_SESSION_ENABLED "True")
add_subdirectory(oscillator)
endif()
if (SMTK_ENABLE_PYTHON_WRAPPING)
add_subdirectory(pybind11)
endif()
......@@ -7,8 +7,8 @@
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#ifndef __smtk_session_mesh_CreateUniformGrid_h
#define __smtk_session_mesh_CreateUniformGrid_h
#ifndef smtk_session_mesh_CreateUniformGrid_h
#define smtk_session_mesh_CreateUniformGrid_h
#include "smtk/session/mesh/Exports.h"
......
......@@ -70,22 +70,22 @@
</ChildrenDefinitions>
<DiscreteInfo DefaultIndex="0">
<Structure>
<Structure>
<Value Enum="2">2</Value>
<Items>
<Item>origin2d</Item>
<Item>size2d</Item>
<Item>discretization2d</Item>
</Items>
</Structure>
<Structure>
<Items>
<Item>origin2d</Item>
<Item>size2d</Item>
<Item>discretization2d</Item>
</Items>
</Structure>
<Structure>
<Value Enum="3">3</Value>
<Items>
<Item>origin3d</Item>
<Item>size3d</Item>
<Item>discretization3d</Item>
</Items>
</Structure>
<Items>
<Item>origin3d</Item>
<Item>size3d</Item>
<Item>discretization3d</Item>
</Items>
</Structure>
</DiscreteInfo>
</String>
......
set(oscillatorSrcs
Registrar.cxx
Resource.cxx
SimulationAttribute.cxx
operators/CreateModel.cxx
# operators/Delete.cxx
operators/EditDomain.cxx
operators/EditSource.cxx
operators/Export.cxx
operators/Read.cxx
operators/Write.cxx
)
set(oscillatorHeaders
Registrar.h
Resource.h
SimulationAttribute.h
operators/CreateModel.h
# operators/Delete.h
operators/EditDomain.h
operators/EditSource.h
operators/Export.h
operators/Read.h
operators/Write.h
)
add_library(smtkOscillatorSession ${oscillatorSrcs})
target_link_libraries(smtkOscillatorSession
PUBLIC
smtkCore
PRIVATE
${__dependencies}
)
smtk_export_header(smtkOscillatorSession Exports.h)
smtk_install_library(smtkOscillatorSession)
# Operators which have XML descriptions in separate files
# need to have it encoded as a string in a header.
# We do not need the path to the generated header (appended
# to oscillatorOperatorXML) since the operators themselves include
# the header in their implementations.
smtk_operation_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/CreateModel.sbt" oscillatorOperatorXML)
# smtk_operation_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/Delete.sbt" oscillatorOperatorXML)
smtk_operation_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/EditDomain.sbt" oscillatorOperatorXML)
smtk_operation_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/EditSource.sbt" oscillatorOperatorXML)
smtk_operation_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/Export.sbt" oscillatorOperatorXML)
smtk_operation_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/Read.sbt" oscillatorOperatorXML)
smtk_operation_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/Write.sbt" oscillatorOperatorXML)
# This is not an operation but a simulation attribute. However, we can use
# the XML encoding the same way:
smtk_operation_xml("${CMAKE_CURRENT_SOURCE_DIR}/SimulationAttribute.sbt" oscillatorOperatorXML)
# Install the headers
smtk_public_headers(smtkOscillatorSession ${oscillatorHeaders})
#if (SMTK_ENABLE_QT_SUPPORT)
# add_subdirectory(qt)
#endif()
if (SMTK_ENABLE_PARAVIEW_SUPPORT)
add_subdirectory(plugin)
endif()
if (SMTK_ENABLE_PYTHON_WRAPPING)
set(oscillatorPySrcs)
set(oscillator_pymodulefiles)
set(oscillator_pyxmlfiles)
foreach(pyfile ${oscillatorPySrcs})
get_filename_component(filename ${pyfile} NAME)
file(RELATIVE_PATH relativedir ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/${pyfile}"
"${CMAKE_BINARY_DIR}/${relativedir}/${filename}" @ONLY
)
list(APPEND oscillator_pymodulefiles "${CMAKE_BINARY_DIR}/${relativedir}/${filename}")
endforeach()
foreach(pyfile ${oscillator_pyxmlfiles})
get_filename_component(filename ${pyfile} NAME)
file(RELATIVE_PATH relativefile ${PROJECT_BINARY_DIR} ${pyfile})
configure_file(
"${pyfile}"
"${CMAKE_BINARY_DIR}/${relativefile}" @ONLY
)
list(APPEND oscillator_pymodulefiles "${CMAKE_BINARY_DIR}/${relativefile}")
endforeach()
file(RELATIVE_PATH relativedir ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
install(
FILES ${oscillator_pymodulefiles}
DESTINATION "${SMTK_PYTHON_MODULEDIR}/${relativedir}"
)
# add_subdirectory(pybind11)
endif()
if (SMTK_ENABLE_TESTING)
add_subdirectory(testing)
endif()
//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
//=============================================================================
#include "smtk/session/oscillator/Registrar.h"
#include "smtk/session/oscillator/operators/CreateModel.h"
#include "smtk/session/oscillator/operators/EditDomain.h"
#include "smtk/session/oscillator/operators/EditSource.h"
#include "smtk/session/oscillator/operators/Export.h"
#include "smtk/session/oscillator/operators/Read.h"
#include "smtk/session/oscillator/operators/Write.h"
#include "smtk/session/oscillator/Resource.h"
#include "smtk/operation/groups/CreatorGroup.h"
#include "smtk/operation/groups/ExporterGroup.h"
#include "smtk/operation/groups/ImporterGroup.h"
#include "smtk/operation/groups/ReaderGroup.h"
#include "smtk/operation/groups/WriterGroup.h"
namespace smtk
{
namespace session
{
namespace oscillator
{
namespace
{
typedef std::tuple<CreateModel, EditDomain, EditSource, Export, Read, Write> OperationList;
}
void Registrar::registerTo(const smtk::resource::Manager::Ptr& resourceManager)
{
// Providing a write method to the resource manager is what allows
// modelbuilder's pqSMTKSaveResourceBehavior to determine how to write
// the resource when users click "Save Resource" or ⌘ S/⌃ S.
resourceManager->registerResource<smtk::session::oscillator::Resource>(read, write);
}
void Registrar::registerTo(const smtk::operation::Manager::Ptr& operationManager)
{
// Register operations
operationManager->registerOperations<OperationList>();
smtk::operation::CreatorGroup(operationManager)
.registerOperation<smtk::session::oscillator::Resource,
smtk::session::oscillator::EditDomain>();
// smtk::operation::ImporterGroup(operationManager)
// .registerOperation<smtk::session::oscillator::Resource, smtk::session::oscillator::ReadRXFFile>();
// TODO: Export really expects a simulation attribute, not a geometric model.
// This is because the simulation attribute is linked to the geometric model
// and not vice-versa (so there is only a slow path for obtaining the
// simulation attribute from the geometry).
// smtk::operation::ExporterGroup(operationManager)
// .registerOperation<smtk::session::oscillator::Resource, smtk::session::oscillator::Export>();
smtk::operation::ReaderGroup(operationManager)
.registerOperation<smtk::session::oscillator::Resource, smtk::session::oscillator::Read>();
smtk::operation::WriterGroup(operationManager)
.registerOperation<smtk::session::oscillator::Resource, smtk::session::oscillator::Write>();
}
void Registrar::unregisterFrom(const smtk::resource::Manager::Ptr& resourceManager)
{
resourceManager->unregisterResource<smtk::session::oscillator::Resource>();
}
void Registrar::unregisterFrom(const smtk::operation::Manager::Ptr& operationManager)
{
operationManager->unregisterOperations<OperationList>();
}
}
}
}
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#ifndef smtk_session_oscillator_Registrar_h
#define smtk_session_oscillator_Registrar_h
#include "smtk/session/oscillator/Exports.h"
#include "smtk/attribute/Registrar.h"
#include "smtk/mesh/resource/Registrar.h"
#include "smtk/model/Registrar.h"
#include "smtk/operation/Manager.h"
#include "smtk/operation/Registrar.h"
#include "smtk/resource/Manager.h"
namespace smtk
{
namespace session
{
namespace oscillator
{
class SMTKOSCILLATORSESSION_EXPORT Registrar
{
public:
using Dependencies =
std::tuple<operation::Registrar, model::Registrar, attribute::Registrar, mesh::Registrar>;
static void registerTo(const smtk::operation::Manager::Ptr&);
static void unregisterFrom(const smtk::operation::Manager::Ptr&);
static void registerTo(const smtk::resource::Manager::Ptr&);
static void unregisterFrom(const smtk::resource::Manager::Ptr&);
};
}
}
}
#endif
//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
//=============================================================================
#include "smtk/session/oscillator/Resource.h"
#include "smtk/model/Volume.h"
namespace smtk
{
namespace session
{
namespace oscillator
{
Resource::Resource(const smtk::common::UUID& id, resource::Manager::Ptr manager)
: smtk::resource::DerivedFrom<Resource, smtk::model::Resource>(id, manager)
{
}
Resource::Resource(resource::Manager::Ptr manager)
: smtk::resource::DerivedFrom<Resource, smtk::model::Resource>(manager)
{
}
bool Resource::resetDomainTessellation(smtk::model::Volume& domain)
{
auto origin = domain.floatProperty("origin");
auto size = domain.floatProperty("size");
int dimension = static_cast<int>(origin.size());
if (dimension < 2 || dimension > 3)
{
return false;
}
if (static_cast<int>(size.size()) != dimension)
{
return false;
}
// Use the operation info to create or replace the tessellation.
auto tess = domain.resetTessellation();
double corner[3] = { 0, 0, 0 };
for (int ii = 0; ii < (1 << dimension); ++ii)
{
for (int cc = 0; cc < dimension; ++cc)
{
corner[cc] = origin[cc] + ((ii & (1 << cc)) ? size[cc] : 0.0);
}
tess->addCoords(corner);
}
constexpr int edgeEndpoints[12][2] = { { 0, 1 }, { 1, 3 }, { 3, 2 }, { 2, 0 },
{ 4, 5 }, { 5, 7 }, { 7, 6 }, { 6, 4 },
{ 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 } };
int numEdges = (dimension == 2 ? 4 : 12);
for (int ee = 0; ee < numEdges; ++ee)
{
tess->addLine(edgeEndpoints[ee][0], edgeEndpoints[ee][1]);
}
return true;
}
}
}
}
//=========================================================================