Sketcher: Improvement: Horizontal/Vertical Autoconstraint creation with External Geometry

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

This fixes a bug related to:
http://www.freecadweb.org/tracker/view.php?id=2093

that during creation of a geometric element if a vertical/horiz autoconstraint is to be enforced, it is not enforced if the endpoints of the geometric element under creation are
coincident with external geometry.

According to the discussion here:
http://forum.freecadweb.org/viewtopic.php?f=10&t=12254&sid=eacf5bdee068cb71cc54dc5a62a6849d&start=20#p99359

this fixes the bug.

It does not fulfil the request on the ticket as it was decided to still allow an explicit addition of a vertical/horizontal constraint, as
it may be needed in some cases and the user expects to be able to add them, even if it will lead to an overconstrained sketch.

How to reproduce?
1. Create a rectange
2. Pad it
3. Create a new sketch on a face
4. link two corners as "external geometry" (but not the ones of a diagonal)
5. Create a line coincident with the first and second corners, so that the line is horizontal or vertical

In master it will force horiz or vert leading to a overconstrained sketch.
With this patch, the horiz/vert will not be enforced in this case.
This commit is contained in:
Abdullah Tahiri
2015-09-06 11:38:51 +02:00
committed by wmayer
parent 003199d6df
commit 224b3ec7d7
3 changed files with 124 additions and 9 deletions

View File

@@ -3074,6 +3074,95 @@ void SketchObject::rebuildVertexIndex(void)
}
}
const std::vector< std::map<int, Sketcher::PointPos> > SketchObject::getCoincidenceGroups()
{
// this function is different from that in getCoincidentPoints in that:
// - getCoincidentPoints only considers direct coincidence (the points that are linked via a single coincidence)
// - this function provides an array of maps of points, each map containing the points that are coincident by virtue
// of any number of interrelated coincidence constraints (if coincidence 1-2 and coincidence 2-3, {1,2,3} are in that set)
const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues();
std::vector< std::map<int, Sketcher::PointPos> > coincidenttree;
// push the constraints
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it) {
if( (*it)->Type == Sketcher::Coincident ) {
int firstpresentin=-1;
int secondpresentin=-1;
int i=0;
for(std::vector< std::map<int, Sketcher::PointPos> >::const_iterator iti = coincidenttree.begin(); iti != coincidenttree.end(); ++iti,i++) {
// First
std::map<int, Sketcher::PointPos>::const_iterator filiterator;
filiterator = (*iti).find((*it)->First);
if( filiterator != (*iti).end()) {
if((*it)->FirstPos == (*filiterator).second)
firstpresentin = i;
}
// Second
filiterator = (*iti).find((*it)->Second);
if( filiterator != (*iti).end()) {
if((*it)->SecondPos == (*filiterator).second)
secondpresentin = i;
}
}
if ( firstpresentin!=-1 && secondpresentin!=-1) {
// we have to merge those sets into one
coincidenttree[firstpresentin].insert(coincidenttree[secondpresentin].begin(), coincidenttree[secondpresentin].end());
coincidenttree.erase(coincidenttree.begin()+secondpresentin);
}
else if ( firstpresentin==-1 && secondpresentin==-1 ) {
// we do not have any of the values, so create a setCursor
std::map<int, Sketcher::PointPos> tmp;
tmp.insert(std::pair<int, Sketcher::PointPos>((*it)->First,(*it)->FirstPos));
tmp.insert(std::pair<int, Sketcher::PointPos>((*it)->Second,(*it)->SecondPos));
coincidenttree.push_back(tmp);
}
else if ( firstpresentin != -1 ) {
// add to existing group
coincidenttree[firstpresentin].insert(std::pair<int, Sketcher::PointPos>((*it)->Second,(*it)->SecondPos));
}
else { // secondpresentin != -1
// add to existing group
coincidenttree[secondpresentin].insert(std::pair<int, Sketcher::PointPos>((*it)->First,(*it)->FirstPos));
}
}
}
return coincidenttree;
}
void SketchObject::isCoincidentWithExternalGeometry(int GeoId, bool &start_external, bool &mid_external, bool &end_external) {
start_external=false;
mid_external=false;
end_external=false;
const std::vector< std::map<int, Sketcher::PointPos> > coincidenttree = getCoincidenceGroups();
for(std::vector< std::map<int, Sketcher::PointPos> >::const_iterator it = coincidenttree.begin(); it != coincidenttree.end(); ++it) {
std::map<int, Sketcher::PointPos>::const_iterator geoId1iterator;
geoId1iterator = (*it).find(GeoId);
if( geoId1iterator != (*it).end()) {
// If First is in this set and the first key in this ordered element key is external
if( (*it).begin()->first < 0 ) {
if( (*geoId1iterator).second == Sketcher::start )
start_external=true;
else if ( (*geoId1iterator).second == Sketcher::mid )
mid_external=true;
else if ( (*geoId1iterator).second == Sketcher::end )
end_external=true;
}
}
}
}
void SketchObject::getCoincidentPoints(int GeoId, PointPos PosId, std::vector<int> &GeoIdList,
std::vector<PointPos> &PosIdList)
{