More progress on voxelizing spanners.

This commit is contained in:
Andrzej Kapolka 2014-03-28 20:19:28 -07:00
parent 176d8f746e
commit 7580951b92
5 changed files with 144 additions and 69 deletions

View file

@ -202,7 +202,7 @@ QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) :
InlineAttribute<QRgb>(name, defaultValue) {
}
bool QRgbAttribute::merge(void*& parent, void* children[]) const {
bool QRgbAttribute::merge(void*& parent, void* children[], bool postRead) const {
QRgb firstValue = decodeInline<QRgb>(children[0]);
int totalAlpha = qAlpha(firstValue);
int totalRed = qRed(firstValue) * totalAlpha;
@ -261,7 +261,7 @@ PackedNormalAttribute::PackedNormalAttribute(const QString& name, QRgb defaultVa
QRgbAttribute(name, defaultValue) {
}
bool PackedNormalAttribute::merge(void*& parent, void* children[]) const {
bool PackedNormalAttribute::merge(void*& parent, void* children[], bool postRead) const {
QRgb firstValue = decodeInline<QRgb>(children[0]);
glm::vec3 total = unpackNormal(firstValue) * (float)qAlpha(firstValue);
bool allChildrenEqual = true;
@ -270,7 +270,8 @@ bool PackedNormalAttribute::merge(void*& parent, void* children[]) const {
total += unpackNormal(value) * (float)qAlpha(value);
allChildrenEqual &= (firstValue == value);
}
parent = encodeInline(packNormal(glm::normalize(total)));
float length = glm::length(total);
parent = encodeInline(length < EPSILON ? QRgb() : packNormal(total / length));
return allChildrenEqual;
}
@ -310,13 +311,37 @@ MetavoxelNode* SpannerQRgbAttribute::createMetavoxelNode(
return new MetavoxelNode(value, original);
}
bool SpannerQRgbAttribute::merge(void*& parent, void* children[]) const {
for (int i = 0; i < MERGE_COUNT; i++) {
if (qAlpha(decodeInline<QRgb>(children[i])) != 0) {
return false;
bool SpannerQRgbAttribute::merge(void*& parent, void* children[], bool postRead) const {
if (postRead) {
for (int i = 0; i < MERGE_COUNT; i++) {
if (qAlpha(decodeInline<QRgb>(children[i])) != 0) {
return false;
}
}
return true;
}
return true;
QRgb parentValue = decodeInline<QRgb>(parent);
int totalAlpha = qAlpha(parentValue) * Attribute::MERGE_COUNT;
int totalRed = qRed(parentValue) * totalAlpha;
int totalGreen = qGreen(parentValue) * totalAlpha;
int totalBlue = qBlue(parentValue) * totalAlpha;
bool allChildrenTransparent = true;
for (int i = 0; i < Attribute::MERGE_COUNT; i++) {
QRgb value = decodeInline<QRgb>(children[i]);
int alpha = qAlpha(value);
totalRed += qRed(value) * alpha;
totalGreen += qGreen(value) * alpha;
totalBlue += qBlue(value) * alpha;
totalAlpha += alpha;
allChildrenTransparent &= (alpha == 0);
}
if (totalAlpha == 0) {
parent = encodeInline(QRgb());
} else {
parent = encodeInline(qRgba(totalRed / totalAlpha, totalGreen / totalAlpha,
totalBlue / totalAlpha, totalAlpha / MERGE_COUNT));
}
return allChildrenTransparent;
}
AttributeValue SpannerQRgbAttribute::inherit(const AttributeValue& parentValue) const {
@ -341,13 +366,27 @@ MetavoxelNode* SpannerPackedNormalAttribute::createMetavoxelNode(
return new MetavoxelNode(value, original);
}
bool SpannerPackedNormalAttribute::merge(void*& parent, void* children[]) const {
for (int i = 0; i < MERGE_COUNT; i++) {
if (qAlpha(decodeInline<QRgb>(children[i])) != 0) {
return false;
bool SpannerPackedNormalAttribute::merge(void*& parent, void* children[], bool postRead) const {
if (postRead) {
for (int i = 0; i < MERGE_COUNT; i++) {
if (qAlpha(decodeInline<QRgb>(children[i])) != 0) {
return false;
}
}
return true;
}
return true;
QRgb parentValue = decodeInline<QRgb>(parent);
glm::vec3 total = unpackNormal(parentValue) * (float)(qAlpha(parentValue) * Attribute::MERGE_COUNT);
bool allChildrenTransparent = true;
for (int i = 0; i < Attribute::MERGE_COUNT; i++) {
QRgb value = decodeInline<QRgb>(children[i]);
int alpha = qAlpha(value);
total += unpackNormal(value) * (float)alpha;
allChildrenTransparent &= (alpha == 0);
}
float length = glm::length(total);
parent = encodeInline(length < EPSILON ? QRgb() : packNormal(total / length));
return allChildrenTransparent;
}
AttributeValue SpannerPackedNormalAttribute::inherit(const AttributeValue& parentValue) const {
@ -373,7 +412,7 @@ void SharedObjectAttribute::write(Bitstream& out, void* value, bool isLeaf) cons
}
}
bool SharedObjectAttribute::merge(void*& parent, void* children[]) const {
bool SharedObjectAttribute::merge(void*& parent, void* children[], bool postRead) const {
SharedObjectPointer firstChild = decodeInline<SharedObjectPointer>(children[0]);
for (int i = 1; i < MERGE_COUNT; i++) {
if (firstChild != decodeInline<SharedObjectPointer>(children[i])) {
@ -413,7 +452,7 @@ MetavoxelNode* SharedObjectSetAttribute::createMetavoxelNode(
return new MetavoxelNode(value, original);
}
bool SharedObjectSetAttribute::merge(void*& parent, void* children[]) const {
bool SharedObjectSetAttribute::merge(void*& parent, void* children[], bool postRead) const {
for (int i = 0; i < MERGE_COUNT; i++) {
if (!decodeInline<SharedObjectSet>(children[i]).isEmpty()) {
return false;

View file

@ -115,7 +115,6 @@ public:
template<class T> void setInlineValue(T value) { _value = encodeInline(value); }
template<class T> T getInlineValue() const { return decodeInline<T>(_value); }
template<class T> T getSafeInlineValue() const { return _attribute ? decodeInline<T>(_value) : T(); }
void* copy() const;
@ -205,8 +204,9 @@ public:
virtual bool equal(void* first, void* second) const = 0;
/// Merges the value of a parent and its children.
/// \param postRead whether or not the merge is happening after a read
/// \return whether or not the children and parent values are all equal
virtual bool merge(void*& parent, void* children[]) const = 0;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const = 0;
/// Given the parent value, returns the value that children should inherit (either the parent value or the default).
virtual AttributeValue inherit(const AttributeValue& parentValue) const { return parentValue; }
@ -274,7 +274,7 @@ public:
Q_INVOKABLE QRgbAttribute(const QString& name = QString(), QRgb defaultValue = QRgb());
virtual bool merge(void*& parent, void* children[]) const;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual void* mix(void* first, void* second, float alpha) const;
@ -293,7 +293,7 @@ public:
Q_INVOKABLE PackedNormalAttribute(const QString& name = QString(), QRgb defaultValue = QRgb());
virtual bool merge(void*& parent, void* children[]) const;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual void* mix(void* first, void* second, float alpha) const;
};
@ -317,7 +317,7 @@ public:
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
virtual bool merge(void*& parent, void* children[]) const;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
};
@ -335,7 +335,7 @@ public:
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
virtual bool merge(void*& parent, void* children[]) const;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
};
@ -354,7 +354,7 @@ public:
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
virtual bool merge(void*& parent, void* children[]) const;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual void* createFromVariant(const QVariant& value) const;
@ -382,7 +382,7 @@ public:
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
virtual bool merge(void*& parent, void* children[]) const;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual AttributeValue inherit(const AttributeValue& parentValue) const;

View file

@ -85,7 +85,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor) {
const QVector<AttributePointer>& inputs = visitor.getInputs();
const QVector<AttributePointer>& outputs = visitor.getOutputs();
MetavoxelVisitation firstVisitation = { NULL, visitor, QVector<MetavoxelNode*>(inputs.size() + 1),
QVector<MetavoxelNode*>(outputs.size()), { getMinimum(), _size,
QVector<MetavoxelNode*>(outputs.size()), { NULL, getMinimum(), _size,
QVector<AttributeValue>(inputs.size() + 1), QVector<OwnedAttributeValue>(outputs.size()) } };
for (int i = 0; i < inputs.size(); i++) {
MetavoxelNode* node = _roots.value(inputs.at(i));
@ -169,7 +169,7 @@ template<SpannerUpdateFunction F> int SpannerUpdateVisitor<F>::visit(MetavoxelIn
if (info.size > _longestSide) {
return DEFAULT_ORDER;
}
SharedObjectSet set = info.inputValues.at(0).getSafeInlineValue<SharedObjectSet>();
SharedObjectSet set = info.inputValues.at(0).getInlineValue<SharedObjectSet>();
F(set, _object);
info.outputValues[0] = AttributeValue(_attribute, encodeInline(set));
return STOP_RECURSION;
@ -523,14 +523,17 @@ AttributeValue MetavoxelNode::getAttributeValue(const AttributePointer& attribut
return AttributeValue(attribute, _attributeValue);
}
void MetavoxelNode::mergeChildren(const AttributePointer& attribute) {
void MetavoxelNode::mergeChildren(const AttributePointer& attribute, bool postRead) {
if (isLeaf()) {
return;
}
void* childValues[CHILD_COUNT];
bool allLeaves = true;
for (int i = 0; i < CHILD_COUNT; i++) {
childValues[i] = _children[i]->_attributeValue;
allLeaves &= _children[i]->isLeaf();
}
if (attribute->merge(_attributeValue, childValues) && allLeaves) {
if (attribute->merge(_attributeValue, childValues, postRead) && allLeaves) {
clearChildren(attribute);
}
}
@ -562,7 +565,7 @@ void MetavoxelNode::read(MetavoxelStreamState& state) {
_children[i] = new MetavoxelNode(state.attribute);
_children[i]->read(nextState);
}
mergeChildren(state.attribute);
mergeChildren(state.attribute, true);
}
}
@ -620,7 +623,7 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta
}
}
}
mergeChildren(state.attribute);
mergeChildren(state.attribute, true);
}
}
@ -887,7 +890,7 @@ void SpannerVisitor::prepare() {
int SpannerVisitor::visit(MetavoxelInfo& info) {
for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getSafeInlineValue<SharedObjectSet>()) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->testAndSetVisited()) {
if (!visit(spanner)) {
@ -939,7 +942,7 @@ bool operator<(const SpannerDistance& first, const SpannerDistance& second) {
int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
QVarLengthArray<SpannerDistance, 4> spannerDistances;
for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getSafeInlineValue<SharedObjectSet>()) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->testAndSetVisited()) {
SpannerDistance spannerDistance = { spanner };
@ -989,7 +992,7 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
}
MetavoxelVisitation nextVisitation = { &visitation, visitation.visitor,
QVector<MetavoxelNode*>(visitation.inputNodes.size()), QVector<MetavoxelNode*>(visitation.outputNodes.size()),
{ glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.inputNodes.size()),
{ &visitation.info, glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.inputNodes.size()),
QVector<OwnedAttributeValue>(visitation.outputNodes.size()) } };
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
// the encoded order tells us the child indices for each iteration
@ -1107,7 +1110,7 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin
QScriptValue infoValue = context->argument(0);
QScriptValue minimum = infoValue.property(guide->_minimumHandle);
MetavoxelInfo info = {
glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()),
NULL, glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()),
(float)infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.inputValues,
guide->_visitation->info.outputValues, infoValue.property(guide->_isLeafHandle).toBool() };
@ -1242,7 +1245,7 @@ const QVector<AttributePointer>& Spanner::getVoxelizedAttributes() const {
return emptyVector;
}
bool Spanner::getAttributeValues(MetavoxelInfo& info) const {
bool Spanner::getAttributeValues(MetavoxelInfo& info, bool force) const {
return false;
}
@ -1350,10 +1353,10 @@ const QVector<AttributePointer>& Sphere::getVoxelizedAttributes() const {
return attributes;
}
bool Sphere::getAttributeValues(MetavoxelInfo& info) const {
bool Sphere::getAttributeValues(MetavoxelInfo& info, bool force) const {
// bounds check
Box bounds = info.getBounds();
if (!getBounds().intersects(bounds)) {
if (!(force || getBounds().intersects(bounds))) {
return false;
}
// count the points inside the sphere
@ -1366,15 +1369,16 @@ bool Sphere::getAttributeValues(MetavoxelInfo& info) const {
if (pointsWithin == Box::VERTEX_COUNT) {
// entirely contained
info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline<QRgb>(_color.rgba()));
getNormal(info);
info.outputValues[1] = getNormal(info, _color.alpha());
return false;
}
if (info.size <= getVoxelizationGranularity()) {
if (force || info.size <= getVoxelizationGranularity()) {
// best guess
if (pointsWithin > 0) {
int alpha = _color.alpha() * pointsWithin / Box::VERTEX_COUNT;
info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline<QRgb>(qRgba(
_color.red(), _color.green(), _color.blue(), _color.alpha() * pointsWithin / Box::VERTEX_COUNT)));
getNormal(info);
_color.red(), _color.green(), _color.blue(), alpha)));
info.outputValues[1] = getNormal(info, alpha);
}
return false;
}
@ -1397,19 +1401,23 @@ bool Sphere::blendAttributeValues(MetavoxelInfo& info, bool force) const {
if (pointsWithin == Box::VERTEX_COUNT) {
// entirely contained
info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline<QRgb>(_color.rgba()));
info.outputValues[1] = getNormal(info);
info.outputValues[1] = getNormal(info, _color.alpha());
return false;
}
if (force || info.size <= getVoxelizationGranularity()) {
// best guess
if (pointsWithin > 0) {
int oldAlpha = qAlpha(info.inputValues.at(0).getInlineValue<QRgb>());
const AttributeValue& oldColor = info.outputValues.at(0).getAttribute() ?
info.outputValues.at(0) : info.inputValues.at(0);
const AttributeValue& oldNormal = info.outputValues.at(1).getAttribute() ?
info.outputValues.at(1) : info.inputValues.at(1);
int oldAlpha = qAlpha(oldColor.getInlineValue<QRgb>());
int newAlpha = _color.alpha() * pointsWithin / Box::VERTEX_COUNT;
float combinedAlpha = (float)newAlpha / (oldAlpha + newAlpha);
info.outputValues[0].mix(info.inputValues.at(0), AttributeValue(getAttributes().at(0),
encodeInline<QRgb>(qRgba(_color.red(), _color.green(), _color.blue(),
_color.alpha() * pointsWithin / Box::VERTEX_COUNT))), combinedAlpha);
info.outputValues[1].mix(info.inputValues.at(1), getNormal(info), combinedAlpha);
int baseAlpha = _color.alpha() * pointsWithin / Box::VERTEX_COUNT;
info.outputValues[0].mix(oldColor, AttributeValue(getAttributes().at(0),
encodeInline<QRgb>(qRgba(_color.red(), _color.green(), _color.blue(), baseAlpha))), combinedAlpha);
info.outputValues[1].mix(oldNormal, getNormal(info, baseAlpha), combinedAlpha);
}
return false;
}
@ -1429,20 +1437,19 @@ void Sphere::updateBounds() {
setBounds(Box(getTranslation() - extent, getTranslation() + extent));
}
AttributeValue Sphere::getNormal(MetavoxelInfo& info) const {
AttributeValue Sphere::getNormal(MetavoxelInfo& info, int alpha) const {
glm::vec3 normal = info.getCenter() - getTranslation();
float length = glm::length(normal);
QRgb color;
if (length > EPSILON) {
if (alpha != 0 && length > EPSILON) {
const float NORMAL_SCALE = 127.0f;
float scale = NORMAL_SCALE / length;
const int BYTE_MASK = 0xFF;
color = qRgb((int)(normal.x * scale) & BYTE_MASK, (int)(normal.y * scale) & BYTE_MASK,
(int)(normal.z * scale) & BYTE_MASK);
color = qRgba((int)(normal.x * scale) & BYTE_MASK, (int)(normal.y * scale) & BYTE_MASK,
(int)(normal.z * scale) & BYTE_MASK, alpha);
} else {
const QRgb DEFAULT_NORMAL = 0x007F00;
color = DEFAULT_NORMAL;
color = QRgb();
}
return AttributeValue(getAttributes().at(1), encodeInline<QRgb>(color));
}

View file

@ -140,7 +140,7 @@ public:
AttributeValue getAttributeValue(const AttributePointer& attribute) const;
void* getAttributeValue() const { return _attributeValue; }
void mergeChildren(const AttributePointer& attribute);
void mergeChildren(const AttributePointer& attribute, bool postRead = false);
MetavoxelNode* getChild(int index) const { return _children[index]; }
void setChild(int index, MetavoxelNode* child) { _children[index] = child; }
@ -185,6 +185,7 @@ private:
class MetavoxelInfo {
public:
MetavoxelInfo* parentInfo;
glm::vec3 minimum; ///< the minimum extent of the area covered by the voxel
float size; ///< the size of the voxel in all dimensions
QVector<AttributeValue> inputValues;
@ -436,7 +437,7 @@ public:
/// Sets the attribute values associated with this spanner in the supplied info.
/// \return true to recurse, false to stop
virtual bool getAttributeValues(MetavoxelInfo& info) const;
virtual bool getAttributeValues(MetavoxelInfo& info, bool force = false) const;
/// Blends the attribute values associated with this spanner into the supplied info.
/// \param force if true, blend even if we would normally subdivide
@ -536,7 +537,7 @@ public:
virtual const QVector<AttributePointer>& getAttributes() const;
virtual const QVector<AttributePointer>& getVoxelizedAttributes() const;
virtual bool getAttributeValues(MetavoxelInfo& info) const;
virtual bool getAttributeValues(MetavoxelInfo& info, bool force = false) const;
virtual bool blendAttributeValues(MetavoxelInfo& info, bool force = false) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
@ -554,7 +555,7 @@ private slots:
private:
AttributeValue getNormal(MetavoxelInfo& info) const;
AttributeValue getNormal(MetavoxelInfo& info, int alpha) const;
QColor _color;
};

View file

@ -104,42 +104,64 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh
spanner(spanner) {
}
class InsertSpannerEditVisitor : public MetavoxelVisitor {
class UpdateSpannerVisitor : public MetavoxelVisitor {
public:
InsertSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner);
UpdateSpannerVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner);
virtual int visit(MetavoxelInfo& info);
private:
Spanner* _spanner;
float _longestSide;
float _voxelizationSize;
int _steps;
};
InsertSpannerEditVisitor::InsertSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) :
MetavoxelVisitor(attributes, attributes),
UpdateSpannerVisitor::UpdateSpannerVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) :
MetavoxelVisitor(QVector<AttributePointer>() << attributes << AttributeRegistry::getInstance()->getSpannersAttribute(),
attributes),
_spanner(spanner),
_longestSide(qMax(spanner->getBounds().getLongestSide(), spanner->getPlacementGranularity()) * 2.0f /
AttributeRegistry::getInstance()->getSpannersAttribute()->getLODThresholdMultiplier()) {
_voxelizationSize(qMax(spanner->getBounds().getLongestSide(), spanner->getPlacementGranularity()) * 2.0f /
AttributeRegistry::getInstance()->getSpannersAttribute()->getLODThresholdMultiplier()),
_steps(roundf(logf(AttributeRegistry::getInstance()->getSpannersAttribute()->getLODThresholdMultiplier()) /
logf(2.0f) - 2.0f)) {
}
int InsertSpannerEditVisitor::visit(MetavoxelInfo& info) {
int UpdateSpannerVisitor::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_spanner->getBounds())) {
return STOP_RECURSION;
}
if (info.size > _longestSide) {
return DEFAULT_ORDER;
MetavoxelInfo* parentInfo = info.parentInfo;
for (int i = 0; i < _steps && parentInfo; i++) {
parentInfo = parentInfo->parentInfo;
}
_spanner->blendAttributeValues(info, true);
return STOP_RECURSION;
if (!parentInfo) {
for (int i = 0; i < _outputs.size(); i++) {
info.outputValues[i] = AttributeValue(_outputs.at(i));
}
return (info.size > _voxelizationSize) ? DEFAULT_ORDER : STOP_RECURSION;
}
SharedObjectSet objects = parentInfo->inputValues.at(_outputs.size()).getInlineValue<SharedObjectSet>();
if (objects.isEmpty()) {
for (int i = 0; i < _outputs.size(); i++) {
info.outputValues[i] = AttributeValue(_outputs.at(i));
}
return (info.size > _voxelizationSize) ? DEFAULT_ORDER : STOP_RECURSION;
}
SharedObjectSet::const_iterator it = objects.constBegin();
static_cast<const Spanner*>(it->data())->getAttributeValues(info, true);
for (it++; it != objects.constEnd(); it++) {
static_cast<const Spanner*>(it->data())->blendAttributeValues(info, true);
}
return (info.size > _voxelizationSize) ? DEFAULT_ORDER : STOP_RECURSION;
}
void InsertSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
data.insert(attribute, this->spanner);
Spanner* spanner = static_cast<Spanner*>(this->spanner.data());
InsertSpannerEditVisitor visitor(spanner->getVoxelizedAttributes(), spanner);
UpdateSpannerVisitor visitor(spanner->getVoxelizedAttributes(), spanner);
data.guide(visitor);
}
@ -154,7 +176,13 @@ void RemoveSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& o
qDebug() << "Missing object to remove" << id;
return;
}
// keep a strong reference to the object
SharedObjectPointer sharedPointer = object;
data.remove(attribute, object);
Spanner* spanner = static_cast<Spanner*>(object);
UpdateSpannerVisitor visitor(spanner->getVoxelizedAttributes(), spanner);
data.guide(visitor);
}
ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) :