Sketcher: Geometry state synchronisation

========================================

The geometry state stored in the geometryFacade is modified following a mutable model
(without setting the Geometry property on Constraint change), in order to avoid coupling
the addition/removal of a constraint with a change of the Geometry Property.

This design decision however interferes with the ability of the Geometry property to restore
the correct geometry state upon redo/undo.

While such a situation is rare in the case of Internal Alignment geometry, because constraint
addition/removal is performed with the corresponding geometry addition/removal (within the same
transaction. That is not the case with the Block constraint (or another future general case where
the geometry state may be applied).

This commit leverages the synchronisation mechanism already in use for non-properties (e.g. external geometry or
vertex indices) to check and synchronise geometry state upon undo/redo and restore.

Bonus:
- addGeometryState is refactored to separate the checking logic from the setting logic.
This commit is contained in:
Abdullah Tahiri
2021-02-09 07:48:27 +01:00
parent 40c99417bd
commit 26c060f64f
2 changed files with 109 additions and 81 deletions

View File

@@ -1179,85 +1179,16 @@ void SketchObject::addGeometryState(const Constraint* cstr) const
{
const std::vector< Part::Geometry * > &vals = getInternalGeometry();
if(cstr->Type == InternalAlignment) {
Sketcher::InternalType::InternalType constraintInternalAlignment = InternalType::None;
bool constraintBlockedState = false;
switch(cstr->AlignmentType){
case Undef:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::None);
break;
}
case EllipseMajorDiameter:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::EllipseMajorDiameter);
break;
}
case EllipseMinorDiameter:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::EllipseMinorDiameter);
break;
}
case EllipseFocus1:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::EllipseFocus1);
break;
}
case EllipseFocus2:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::EllipseFocus2);
break;
}
case HyperbolaMajor:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::HyperbolaMajor);
break;
}
case HyperbolaMinor:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::HyperbolaMinor);
break;
}
case HyperbolaFocus:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::HyperbolaFocus);
break;
}
case ParabolaFocus:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::ParabolaFocus);
break;
}
case BSplineControlPoint:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::BSplineControlPoint);
// handle constraint as adimensional
break;
}
case BSplineKnotPoint:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::BSplineKnotPoint);
break;
}
}
}
// Assign Blocked geometry mode
if(cstr->Type == Block){
if (getInternalTypeState(cstr, constraintInternalAlignment)) {
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setBlocked();
gf->setInternalType(constraintInternalAlignment);
}
else if (getBlockedState(cstr, constraintBlockedState)) {
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setBlocked(constraintBlockedState);
}
}
@@ -7669,9 +7600,93 @@ void SketchObject::onUndoRedoFinished()
// such a recompute
Constraints.checkConstraintIndices(getHighestCurveIndex(),-getExternalGeometryCount()); // in case it is redoing an operation with invalid data.
acceptGeometry();
synchroniseGeometryState();
solve();
}
void SketchObject::synchroniseGeometryState()
{
const std::vector< Part::Geometry * > &vals = getInternalGeometry();
for(size_t i = 0 ; i < vals.size() ; i++) {
auto gf = GeometryFacade::getFacade(vals[i]);
auto facadeInternalAlignment = gf->getInternalType();
auto facadeBlockedState = gf->getBlocked();
Sketcher::InternalType::InternalType constraintInternalAlignment = InternalType::None;
bool constraintBlockedState = false;
for (auto cstr : Constraints.getValues()) {
getInternalTypeState(cstr, constraintInternalAlignment);
getBlockedState(cstr, constraintBlockedState);
}
if(constraintInternalAlignment != facadeInternalAlignment)
gf->setInternalType(constraintInternalAlignment);
if(constraintBlockedState != facadeBlockedState)
gf->setBlocked(constraintBlockedState);
}
}
bool SketchObject::getInternalTypeState(const Constraint * cstr, Sketcher::InternalType::InternalType & internaltypestate) const
{
if(cstr->Type == InternalAlignment) {
switch(cstr->AlignmentType){
case Undef:
internaltypestate = InternalType::None;
break;
case EllipseMajorDiameter:
internaltypestate = InternalType::EllipseMajorDiameter;
break;
case EllipseMinorDiameter:
internaltypestate = InternalType::EllipseMinorDiameter;
break;
case EllipseFocus1:
internaltypestate = InternalType::EllipseFocus1;
break;
case EllipseFocus2:
internaltypestate = InternalType::EllipseFocus2;
break;
case HyperbolaMajor:
internaltypestate = InternalType::HyperbolaMajor;
break;
case HyperbolaMinor:
internaltypestate = InternalType::HyperbolaMinor;
break;
case HyperbolaFocus:
internaltypestate = InternalType::HyperbolaFocus;
break;
case ParabolaFocus:
internaltypestate = InternalType::ParabolaFocus;
break;
case BSplineControlPoint:
internaltypestate = InternalType::BSplineControlPoint;
break;
case BSplineKnotPoint:
internaltypestate = InternalType::BSplineKnotPoint;
break;
}
return true;
}
return false;
}
bool SketchObject::getBlockedState(const Constraint * cstr, bool & blockedstate) const
{
if(cstr->Type == Block) {
blockedstate = true;
return true;
}
return false;
}
void SketchObject::onDocumentRestored()
{
try {
@@ -7690,6 +7705,7 @@ void SketchObject::restoreFinished()
validateExternalLinks();
rebuildExternalGeometry();
Constraints.acceptGeometry(getCompleteGeometry());
synchroniseGeometryState();
// this may happen when saving a sketch directly in edit mode
// but never performed a recompute before
if (Shape.getValue().IsNull() && hasConflicts() == 0) {