AngleViaPoint Constraint
AngleViaPoint: fixes in UI routines + new messages Goofed undo message in tangency via point is fixed. Forgotten updateActive, clearSelection have been added. New more informative error messages for tangent constraint. AngleViaPoint: using it instead of via line tangency * replaced the helper construction line for ellipse-to-ellipse and similar tangency with a point. Using tangent-via-point there * deleted tangency via line for point-to-point on (cherry picked from commit 9e3fa8c8de0f49c0ef3c978e015eb905358dbdd9) AngleViaPoint: internal/external tangency locking *Added automatic tangency type lockdown for all new constraints (only for point-wise tangency). Tangency type is stored in the constraint datum field, as an angle value shifted by Pi/2 (to be able to treat 0.0 as undefined type). Added ability to switch the tangency by setting datum value from python (can be abused by passing arbitrary angle). Further simplified the tangency related code in Sketch.cpp. AngleViaPoint: added license to Geo.cpp AngleViaPoint: renames in Constraints.cpp/.h Changed some names to increase self-explanatoryness: bool "remapped" renamed to "pvecChangedFlag" "ReconstructEverything()" renamed to "ReconstructGeomPointers()" AngleViaPoint: renames in Constraints.cpp/.h Changed some names to increase self-explanatoryness: bool "remapped" renamed to "pvecChangedFlag" "ReconstructEverything()" renamed to "ReconstructGeomPointers()" AngleViaPoint: using for endpoint perpendicularity + direction lockdown, just as with tangency. + quite a lot of old code is gone because of that AngleViaPoint: perp-ty UI routine made similar to tangent (Git has made a very messy diff.) The changes are: * Perpendicularity-via-point (3-element selection) support added. * Endpoint-to-curve and endpoint-to-endpoint supports all shape combinations. * a bit of code cleanup and clarifications. AngleViaPoint: placement of perpendicular icon in 3d view AngleViaPoint: fix: allow setDatum of perpendicular constraint AngleViaPoint: fix: centers of ellipses are not endpoints isSimpleVertex used to return false for centers of ellipses and arcs of ellipses, which made them being accepted for point-to-point tangency. Should be fixed forever, mo more changes are expected to be necessary for new types of geometry. AngleViaPoint: precalc with OCC (work in progress) Work in progress (not yet working). Using OCC's tangent to replace implementation of SketchObject::calculateAngleViaPoint. AngleViaPoint: fix math: normal now points inwards, where it was intended initially and goofed up. AngleViaPoint: adding comments to the code AngleViaPoint: using GeomCurve::closestParameterToBasicCurve for angle precalculation AngleViaPoint: Py method: changeConstraintsLocking changeConstraintsLocking(True) - locks/re-locks all lockable tangency/perpendicularity constraints of the sketch (applicable to existing sketches). changeConstraintsLocking(False) - removes locking information from lockable constraints AngleViaPoint: final SketchObject::calculateAngleViaPoint Now, finally, using OCC functionality (thanks Abdullah!), without composing temporary Sketch object.
This commit is contained in:
@@ -194,7 +194,9 @@ int SketchObject::setDatum(int ConstrId, double Datum)
|
||||
type != DistanceX &&
|
||||
type != DistanceY &&
|
||||
type != Radius &&
|
||||
type != Angle)
|
||||
type != Angle &&
|
||||
type != Tangent && //for tangent, value==0 is autodecide, value==Pi/2 is external and value==-Pi/2 is internal
|
||||
type != Perpendicular)
|
||||
return -1;
|
||||
|
||||
if ((type == Distance || type == Radius) && Datum <= 0)
|
||||
@@ -435,13 +437,32 @@ int SketchObject::setConstruction(int GeoId, bool on)
|
||||
return 0;
|
||||
}
|
||||
|
||||
//ConstraintList is used only to make copies.
|
||||
int SketchObject::addConstraints(const std::vector<Constraint *> &ConstraintList)
|
||||
{
|
||||
const std::vector< Constraint * > &vals = this->Constraints.getValues();
|
||||
|
||||
std::vector< Constraint * > newVals(vals);
|
||||
newVals.insert(newVals.end(), ConstraintList.begin(), ConstraintList.end());
|
||||
|
||||
//test if tangent constraints have been added; AutoLockTangency.
|
||||
std::vector< Constraint * > tbd;//list of temporary copies that need to be deleted
|
||||
for(int i = newVals.size()-ConstraintList.size(); i<newVals.size(); i++){
|
||||
if( newVals[i]->Type == Tangent || newVals[i]->Type == Perpendicular ){
|
||||
Constraint *constNew = newVals[i]->clone();
|
||||
AutoLockTangencyAndPerpty(constNew);
|
||||
tbd.push_back(constNew);
|
||||
newVals[i] = constNew;
|
||||
}
|
||||
}
|
||||
|
||||
this->Constraints.setValues(newVals);
|
||||
|
||||
//clean up - delete temporary copies of constraints that were made to affect the constraints
|
||||
for(int i=0; i<tbd.size(); i++){
|
||||
delete (tbd[i]);
|
||||
}
|
||||
|
||||
return this->Constraints.getSize()-1;
|
||||
}
|
||||
|
||||
@@ -451,6 +472,10 @@ int SketchObject::addConstraint(const Constraint *constraint)
|
||||
|
||||
std::vector< Constraint * > newVals(vals);
|
||||
Constraint *constNew = constraint->clone();
|
||||
|
||||
if (constNew->Type == Tangent || constNew->Type == Perpendicular)
|
||||
AutoLockTangencyAndPerpty(constNew);
|
||||
|
||||
newVals.push_back(constNew);
|
||||
this->Constraints.setValues(newVals);
|
||||
delete constNew;
|
||||
@@ -2264,16 +2289,35 @@ void SketchObject::validateConstraints()
|
||||
}
|
||||
}
|
||||
|
||||
//This function is necessary for precalculation of an angle when adding
|
||||
// an angle constraint. It is also used here, in SketchObject, to
|
||||
// lock down the type of tangency/perpendicularity.
|
||||
double SketchObject::calculateAngleViaPoint(int GeoId1, int GeoId2, double px, double py)
|
||||
{
|
||||
//DeepSOIC: this may be slow, but I wanted to reuse the conversion from Geometry to GCS shapes that is done in Sketch
|
||||
Sketcher::Sketch sk;
|
||||
int i1 = sk.addGeometry(this->getGeometry(GeoId1));
|
||||
int i2 = sk.addGeometry(this->getGeometry(GeoId2));
|
||||
const Part::GeomCurve &g1 = *(dynamic_cast<const Part::GeomCurve*>(this->getGeometry(GeoId1)));
|
||||
const Part::GeomCurve &g2 = *(dynamic_cast<const Part::GeomCurve*>(this->getGeometry(GeoId2)));
|
||||
Base::Vector3d p(px, py, 0.0);
|
||||
|
||||
return sk.calculateAngleViaPoint(i1,i2,px,py);
|
||||
double u1 = 0.0;
|
||||
double u2 = 0.0;
|
||||
if (! g1.closestParameterToBasicCurve(p, u1) ) throw Base::Exception("SketchObject::calculateAngleViaPoint: closestParameter(curve1) failed!");
|
||||
if (! g2.closestParameterToBasicCurve(p, u2) ) throw Base::Exception("SketchObject::calculateAngleViaPoint: closestParameter(curve2) failed!");
|
||||
|
||||
gp_Dir tan1, tan2;
|
||||
if (! g1.tangent(u1,tan1) ) throw Base::Exception("SketchObject::calculateAngleViaPoint: tangent1 failed!");
|
||||
if (! g2.tangent(u2,tan2) ) throw Base::Exception("SketchObject::calculateAngleViaPoint: tangent2 failed!");
|
||||
|
||||
assert(abs(tan1.Z())<0.0001);
|
||||
assert(abs(tan2.Z())<0.0001);
|
||||
|
||||
double ang = atan2(-tan2.X()*tan1.Y()+tan2.Y()*tan1.X(), tan2.X()*tan1.X() + tan2.Y()*tan1.Y());
|
||||
return ang;
|
||||
}
|
||||
|
||||
//Tests if the provided point lies exactly in a curve (satisfies
|
||||
// point-on-object constraint). It is used to decide whether it is nesessary to
|
||||
// constrain a point onto curves when 3-element selection tangent-via-point-like
|
||||
// constraints are applied.
|
||||
bool SketchObject::isPointOnCurve(int geoIdCurve, double px, double py)
|
||||
{
|
||||
//DeepSOIC: this may be slow, but I wanted to reuse the existing code
|
||||
@@ -2288,6 +2332,7 @@ bool SketchObject::isPointOnCurve(int geoIdCurve, double px, double py)
|
||||
return err*err < 10.0*sk.getSolverPrecision();
|
||||
}
|
||||
|
||||
//This one was done just for fun to see to what precision the constraints are solved.
|
||||
double SketchObject::calculateConstraintError(int ConstrId)
|
||||
{
|
||||
Sketcher::Sketch sk;
|
||||
@@ -2409,6 +2454,124 @@ int SketchObject::getVertexIndexGeoPos(int GeoId, PointPos PosId) const
|
||||
return -1;
|
||||
}
|
||||
|
||||
///changeConstraintsLocking locks or unlocks all tangent and perpendicular
|
||||
/// constraints. (Constraint locking prevents it from flipping to another valid
|
||||
/// configuration, when e.g. external geometry is updated from outside.) The
|
||||
/// sketch solve is not triggered by the function, but the SketchObject is
|
||||
/// touched (a recompute will be necessary). The geometry should not be affected
|
||||
/// by the function.
|
||||
///The bLock argument specifies, what to do. If true, all constraints are
|
||||
/// unlocked and locked again. If false, all tangent and perp. constraints are
|
||||
/// unlocked.
|
||||
int SketchObject::changeConstraintsLocking(bool bLock)
|
||||
{
|
||||
int cntSuccess = 0;
|
||||
int cntToBeAffected = 0;//==cntSuccess+cntFail
|
||||
const std::vector< Constraint * > &vals = this->Constraints.getValues();
|
||||
|
||||
std::vector< Constraint * > newVals(vals);//modifiable copy of pointers array
|
||||
|
||||
std::vector< Constraint * > tbd;//list of temporary Constraint copies that need to be deleted later
|
||||
|
||||
for(int i = 0; i<newVals.size(); i++){
|
||||
if( newVals[i]->Type == Tangent || newVals[i]->Type == Perpendicular ){
|
||||
//create a constraint copy, affect it, replace the pointer
|
||||
cntToBeAffected++;
|
||||
Constraint *constNew = newVals[i]->clone();
|
||||
bool ret = AutoLockTangencyAndPerpty(constNew, /*bForce=*/true, bLock);
|
||||
if (ret) cntSuccess++;
|
||||
tbd.push_back(constNew);
|
||||
newVals[i] = constNew;
|
||||
}
|
||||
}
|
||||
|
||||
this->Constraints.setValues(newVals);
|
||||
|
||||
//clean up - delete temporary copies of constraints that were made to affect the constraints
|
||||
for(int i=0; i<tbd.size(); i++){
|
||||
delete (tbd[i]);
|
||||
}
|
||||
|
||||
Base::Console().Log("ChangeConstraintsLocking: affected %i of %i tangent/perp constraints\n",
|
||||
cntSuccess, cntToBeAffected);
|
||||
|
||||
return cntSuccess;
|
||||
}
|
||||
|
||||
///Locks tangency/perpendicularity type of such a constraint.
|
||||
///The constraint passed must be writable (i.e. the one that is not
|
||||
/// yet in the constraint list).
|
||||
///Tangency type (internal/external) is derived from current geometry
|
||||
/// the constraint refers to.
|
||||
///Same for perpendicularity type.
|
||||
///
|
||||
///This function catches exceptions, because it's not a reason to
|
||||
/// not create a constraint if tangency/perp-ty type cannot be determined.
|
||||
///
|
||||
///Arguments:
|
||||
/// cstr - pointer to a constraint to be locked/unlocked
|
||||
/// bForce - specifies whether to ignore tha already locked constraint or not.
|
||||
/// bLock - specufies whether to lock the constraint or not (if bForce is
|
||||
/// true, the constraint gets unlocked, otherwise nothing is done at all).
|
||||
///
|
||||
///Return values:
|
||||
/// true - success.
|
||||
/// false - fail (this indicates an error, or that a constraint locking isn't supported).
|
||||
bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool bLock)
|
||||
{
|
||||
try{
|
||||
assert ( cstr->Type == Tangent || cstr->Type == Perpendicular);
|
||||
if(cstr->Value != 0.0 && ! bForce) /*tangency type already set. If not bForce - don't touch.*/
|
||||
return true;
|
||||
if(!bLock){
|
||||
cstr->Value=0.0;//reset
|
||||
} else {
|
||||
//decide on tangency type. Write the angle value into the datum field of the constraint.
|
||||
int geoId1, geoId2, geoIdPt;
|
||||
PointPos posPt;
|
||||
geoId1 = cstr->First;
|
||||
geoId2 = cstr->Second;
|
||||
geoIdPt = cstr->Third;
|
||||
posPt = cstr->ThirdPos;
|
||||
if (geoIdPt == Constraint::GeoUndef){//not tangent-via-point, try endpoint-to-endpoint...
|
||||
geoIdPt = cstr->First;
|
||||
posPt = cstr->FirstPos;
|
||||
}
|
||||
if (posPt == none){//not endpoint-to-curve and not endpoint-to-endpoint tangent (is simple tangency)
|
||||
//no tangency lockdown is implemented for simple tangency. Do nothing.
|
||||
return false;
|
||||
} else {
|
||||
Base::Vector3d p = getPoint(geoIdPt, posPt);
|
||||
|
||||
//this piece of code is also present in Sketch.cpp, correct for offset
|
||||
//and to do the autodecision for old sketches.
|
||||
double angleOffset = 0.0;//the difference between the datum value and the actual angle to apply. (datum=angle+offset)
|
||||
double angleDesire = 0.0;//the desired angle value (and we are to decide if 180* should be added to it)
|
||||
if (cstr->Type == Tangent) {angleOffset = -M_PI/2; angleDesire = 0.0;}
|
||||
if (cstr->Type == Perpendicular) {angleOffset = 0; angleDesire = M_PI/2;}
|
||||
|
||||
double angleErr = calculateAngleViaPoint(geoId1, geoId2, p.x, p.y) - angleDesire;
|
||||
|
||||
//bring angleErr to -pi..pi
|
||||
if (angleErr > M_PI) angleErr -= M_PI*2;
|
||||
if (angleErr < -M_PI) angleErr += M_PI*2;
|
||||
|
||||
//the autodetector
|
||||
if(abs(angleErr) > M_PI/2 )
|
||||
angleDesire += M_PI;
|
||||
|
||||
cstr->Value = angleDesire + angleOffset; //external tangency. The angle stored is offset by Pi/2 so that a value of 0.0 is invalid and threated as "undecided".
|
||||
}
|
||||
}
|
||||
} catch (Base::Exception& e){
|
||||
//failure to determine tangency type is not a big deal, so a warning.
|
||||
assert(0);//but it shouldn't happen (failure to determine tangency type)!
|
||||
Base::Console().Warning("Error in AutoLockTangency. %s \n", e.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Python Sketcher feature ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
|
||||
Reference in New Issue
Block a user