Skip to content

Commit

Permalink
Sketcher: Constraint-Driven geometry status
Browse files Browse the repository at this point in the history
============================================

This is a new concept which originates from the new ability of sketcher geometry to store a geometry state via
geometry extensions.

The idea is that some geometry state is enforced via constraints (InternalAlignment constraints and Block constraint) which
effectively set the state. However, it is convenient to have direct access of the geometry state from the geometry for representation
(ViewProvider) and for the solver. This is the constraint-driven geometry state concept.

The addition/removal of the constraint defines the life cycle of the geometry state and is responsible for setting and removing
the state, so that geometry state and constraint are kept synchronised.

The life cycle is completed with proper serialisation of the geometry state.

In summary:
1. Upon restore, the stored state is restored and any migration is handled to set the status for legacy files (backwards compatibility)
2. Functionality adding constraints (of the relevant type) calls addGeometryState to set the status
3. Functionality removing constraints (of the relevant type) calls removeGeometryState to remove the status
4. Save mechanism will ensure persistance of the geometry state
  • Loading branch information
abdullahtahiriyo committed Dec 10, 2020
1 parent 593ade1 commit e5eff3f
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 85 deletions.
204 changes: 121 additions & 83 deletions src/Mod/Sketcher/App/SketchObject.cpp
Expand Up @@ -147,7 +147,6 @@ SketchObject::SketchObject()

internaltransaction=false;
managedoperation=false;
afterRestoreMigration=false;
}

SketchObject::~SketchObject()
Expand Down Expand Up @@ -1179,6 +1178,106 @@ int SketchObject::setConstruction(int GeoId, bool on)
return 0;
}

void SketchObject::addGeometryState(const Constraint* cstr) const
{
const std::vector< Part::Geometry * > &vals = getInternalGeometry();

if(cstr->Type == InternalAlignment) {

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);
break;
}
case BSplineKnotPoint:
{
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::BSplineKnotPoint);
break;
}
}
}

// Assign Blocked geometry mode
if(cstr->Type == Block){
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setBlocked();
}
}

void SketchObject::removeGeometryState(const Constraint* cstr) const
{
const std::vector< Part::Geometry * > &vals = getInternalGeometry();

// Assign correct Internal Geometry Type (see SketchGeometryExtension)
if(cstr->Type == InternalAlignment) {
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setInternalType(InternalType::None);
}

// Assign Blocked geometry mode (see SketchGeometryExtension)
if(cstr->Type == Block){
auto gf = GeometryFacade::getFacade(vals[cstr->First]);
gf->setBlocked(false);
}
}

//ConstraintList is used only to make copies.
int SketchObject::addConstraints(const std::vector<Constraint *> &ConstraintList)
{
Expand All @@ -1204,6 +1303,8 @@ int SketchObject::addConstraints(const std::vector<Constraint *> &ConstraintList
if( cnew->Type == Tangent || cnew->Type == Perpendicular ){
AutoLockTangencyAndPerpty(cnew);
}

addGeometryState(cnew);
}

this->Constraints.setValues(std::move(newVals));
Expand Down Expand Up @@ -1272,6 +1373,8 @@ int SketchObject::addConstraint(const Constraint *constraint)
if (constNew->Type == Tangent || constNew->Type == Perpendicular)
AutoLockTangencyAndPerpty(constNew);

addGeometryState(constNew);

newVals.push_back(constNew); // add new constraint at the back

this->Constraints.setValues(std::move(newVals));
Expand All @@ -1288,7 +1391,9 @@ int SketchObject::delConstraint(int ConstrId)
return -1;

std::vector< Constraint * > newVals(vals);
newVals.erase(newVals.begin()+ConstrId);
auto ctriter = newVals.begin()+ConstrId;
removeGeometryState(*ctriter);
newVals.erase(ctriter);
this->Constraints.setValues(newVals);

if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver
Expand All @@ -1312,8 +1417,11 @@ int SketchObject::delConstraints(std::vector<int> ConstrIds, bool updategeometry
if (ConstrIds.front() < 0 || ConstrIds.back() >= int(vals.size()))
return -1;

for(auto rit = ConstrIds.rbegin(); rit!=ConstrIds.rend(); rit++)
newVals.erase(newVals.begin()+*rit);
for(auto rit = ConstrIds.rbegin(); rit!=ConstrIds.rend(); rit++) {
auto ctriter = newVals.begin()+*rit;
removeGeometryState(*ctriter);
newVals.erase(ctriter);
}

this->Constraints.setValues(newVals);

Expand Down Expand Up @@ -7340,8 +7448,7 @@ void SketchObject::onUndoRedoFinished()
void SketchObject::onDocumentRestored()
{
try {
if(afterRestoreMigration)
migrateSketch();
migrateSketch();

validateExternalLinks();
rebuildExternalGeometry();
Expand All @@ -7362,8 +7469,7 @@ void SketchObject::onDocumentRestored()
void SketchObject::restoreFinished()
{
try {
if(afterRestoreMigration)
migrateSketch();
migrateSketch();

validateExternalLinks();
rebuildExternalGeometry();
Expand All @@ -7381,84 +7487,16 @@ void SketchObject::restoreFinished()

void SketchObject::migrateSketch(void)
{
const std::vector< Part::Geometry * > &vals = getInternalGeometry();
bool updateGeoState = false;

for( auto c : Constraints.getValues()) {
for( const auto & g : getInternalGeometry() )
if(!g->hasExtension(SketchGeometryExtension::getClassTypeId())) // no extension - legacy file
updateGeoState = true;

// Assign correct Internal Geometry Type
switch(c->AlignmentType){
case Undef:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::None);
break;
}
case EllipseMajorDiameter:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::EllipseMajorDiameter);
break;
}
case EllipseMinorDiameter:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::EllipseMinorDiameter);
break;
}
case EllipseFocus1:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::EllipseFocus1);
break;
}
case EllipseFocus2:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::EllipseFocus2);
break;
}
case HyperbolaMajor:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::HyperbolaMajor);
break;
}
case HyperbolaMinor:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::HyperbolaMinor);
break;
}
case HyperbolaFocus:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::HyperbolaFocus);
break;
}
case ParabolaFocus:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::ParabolaFocus);
break;
}
case BSplineControlPoint:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::BSplineControlPoint);
break;
}
case BSplineKnotPoint:
{
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setInternalType(InternalType::BSplineKnotPoint);
break;
}
}
if(updateGeoState) {
for( auto c : Constraints.getValues()) {

// Assign Blocked geometry mode
if(c->Type == Block){
auto gf = GeometryFacade::getFacade(vals[c->First]);
gf->setBlocked();
addGeometryState(c);
}
}
}
Expand Down
17 changes: 15 additions & 2 deletions src/Mod/Sketcher/App/SketchObject.h
Expand Up @@ -486,13 +486,26 @@ class SketcherExport SketchObject : public Part::Part2DObject

bool AutoLockTangencyAndPerpty(Constraint* cstr, bool bForce = false, bool bLock = true);

// Geometry Extensions is used to store on geometry a state that is enforced by pre-existing constraints
// Like Block constraint and InternalAlignment constraint. This enables (more) convenient handling in ViewProviderSketch
// and solver.
//
// These functions are responsible for updating the Geometry State, currently Geometry Mode (Blocked) and
// Geometry InternalType (BSplineKnot, BSplinePole).
//
// The data life model for handling this state is as follows:
// 1. Upon restore, any migration is handled to set the status for legacy files (backwards compatibility)
// 2. Functionality adding constraints (of the relevant type) calls addGeometryState to set the status
// 3. Functionality removing constraints (of the relevant type) calls removeGeometryState to remove the status
// 4. Save mechanism will ensure persistance.
void addGeometryState(const Constraint* cstr) const;
void removeGeometryState(const Constraint* cstr) const;

SketchAnalysis * analyser;

bool internaltransaction;

bool managedoperation; // indicates whether changes to properties are the deed of SketchObject or not (for input validation)

bool afterRestoreMigration;
};

typedef App::FeaturePythonT<SketchObject> SketchObjectPython;
Expand Down

0 comments on commit e5eff3f

Please sign in to comment.