Sketcher New Feature: Ellipse support
- Ellipse introduction button via (center,majaxis extreme, a point in edge), ellipse is always CCW so that Z axis goes in the positive direction of the sketch - Backwards compatibility with files of previous versions of ellipse not defining a phi angle - Art by Jim (all the icons you see and the XPMs shown on creation of an ellipse) - Element Widget support for ellipses - Box selection for ellipses - Point on Ellipse constraint based on the gardener's method based on Ulrich's function proposal (radcan simplified, i.e. with simplify_radical sage function) - Tangent: Ellipse to Line based on DeepSOIC's geometric formulation (radcan simplified) Sketcher New Feature: Internal Alignment Constraint - The element to which internal alignment is applied has to be selected last. - All other elements are added in the order of priority, taking into account existing elements - Art by Jim (beautiful icons). Sketcher New Feature: Tool to show/hide/restore the internal geometry of an element - New functionality for show/hide internal geometry: toggles between hiding all unused internal geometry elements and showing all internal geometry. The restore function is implicit to the showing all internal geometry Sketcher New Feature: Arc of Ellipse support - Part::Geometry + Python implementation - ArcOfEllipse creation method - Art by Jim (all the icons you see and the XPMs shown on creation of arc of ellipse elements) - Sketcher Element widget for ArcOfEllipse. Bug fix: Select elements associated to constraints works now for foci internal alignment constraints
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
# include <Poly_Polygon3D.hxx>
|
||||
# include <Geom_BSplineCurve.hxx>
|
||||
# include <Geom_Circle.hxx>
|
||||
# include <Geom_Ellipse.hxx>
|
||||
# include <Geom_TrimmedCurve.hxx>
|
||||
# include <Inventor/actions/SoGetBoundingBoxAction.h>
|
||||
# include <Inventor/SoPath.h>
|
||||
@@ -715,7 +716,9 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe
|
||||
const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve);
|
||||
if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
geo->getTypeId() == Part::GeomCircle::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomEllipse::getClassTypeId()||
|
||||
geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { // TODO: ellipse
|
||||
Gui::Command::openCommand("Drag Curve");
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.movePoint(%i,%i,App.Vector(%f,%f,0),%i)"
|
||||
,getObject()->getNameInDocument()
|
||||
@@ -912,8 +915,10 @@ void ViewProviderSketch::editDoubleClicked(void)
|
||||
|
||||
// if its the right constraint
|
||||
if (Constr->Type == Sketcher::Distance ||
|
||||
Constr->Type == Sketcher::DistanceX || Constr->Type == Sketcher::DistanceY ||
|
||||
Constr->Type == Sketcher::Radius || Constr->Type == Sketcher::Angle) {
|
||||
Constr->Type == Sketcher::DistanceX ||
|
||||
Constr->Type == Sketcher::DistanceY ||
|
||||
Constr->Type == Sketcher::Radius ||
|
||||
Constr->Type == Sketcher::Angle) {
|
||||
|
||||
// Coin's SoIdleSensor causes problems on some platform while Qt seems to work properly (#0001517)
|
||||
EditDatumDialog *editDatumDialog = new EditDatumDialog(this, *it);
|
||||
@@ -1161,14 +1166,15 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPo
|
||||
p1 = arc->getCenter();
|
||||
p2 = p1 + radius * Base::Vector3d(cos(angle),sin(angle),0.);
|
||||
}
|
||||
else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo);
|
||||
double radius = circle->getRadius();
|
||||
p1 = circle->getCenter();
|
||||
Base::Vector3d tmpDir = Base::Vector3d(toPos.fX, toPos.fY, 0) - p1;
|
||||
double angle = atan2(tmpDir.y, tmpDir.x);
|
||||
p2 = p1 + radius * Base::Vector3d(cos(angle),sin(angle),0.);
|
||||
} else
|
||||
}
|
||||
else
|
||||
return;
|
||||
} else
|
||||
return;
|
||||
@@ -1815,7 +1821,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s &
|
||||
Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str());
|
||||
}
|
||||
|
||||
} else if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
} else if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
// ----- Check if circle lies inside box selection -----/
|
||||
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(*it);
|
||||
pnt0 = circle->getCenter();
|
||||
@@ -1850,6 +1856,50 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s &
|
||||
}
|
||||
}
|
||||
|
||||
if (bpolyInside) {
|
||||
ss.clear();
|
||||
ss.str("");
|
||||
ss << "Edge" << GeoId + 1;
|
||||
Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(),ss.str().c_str());
|
||||
}
|
||||
}
|
||||
} else if ((*it)->getTypeId() == Part::GeomEllipse::getClassTypeId()) {
|
||||
// ----- Check if circle lies inside box selection -----/
|
||||
const Part::GeomEllipse *ellipse = dynamic_cast<const Part::GeomEllipse *>(*it);
|
||||
pnt0 = ellipse->getCenter();
|
||||
VertexId += 1;
|
||||
|
||||
Plm.multVec(pnt0, pnt0);
|
||||
pnt0 = proj(pnt0);
|
||||
|
||||
if (polygon.Contains(Base::Vector2D(pnt0.x, pnt0.y))) {
|
||||
std::stringstream ss;
|
||||
ss << "Vertex" << VertexId + 1;
|
||||
Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str());
|
||||
|
||||
int countSegments = 12;
|
||||
float segment = float(2 * M_PI) / countSegments;
|
||||
|
||||
// circumscribed polygon radius
|
||||
float a = float(ellipse->getMajorRadius()) / cos(segment/2);
|
||||
float b = float(ellipse->getMinorRadius()) / cos(segment/2);
|
||||
float phi = float(ellipse->getAngleXU());
|
||||
|
||||
bool bpolyInside = true;
|
||||
pnt0 = ellipse->getCenter();
|
||||
float angle = 0.f;
|
||||
for (int i = 0; i < countSegments; ++i, angle += segment) {
|
||||
pnt = Base::Vector3d(pnt0.x + a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi),
|
||||
pnt0.y + a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi),
|
||||
0.f);
|
||||
Plm.multVec(pnt, pnt);
|
||||
pnt = proj(pnt);
|
||||
if (!polygon.Contains(Base::Vector2D(pnt.x, pnt.y))) {
|
||||
bpolyInside = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bpolyInside) {
|
||||
ss.clear();
|
||||
ss.str("");
|
||||
@@ -2082,7 +2132,7 @@ void ViewProviderSketch::updateColor(void)
|
||||
bool hasMaterial = false;
|
||||
|
||||
SoMaterial *m;
|
||||
if (!hasDatumLabel && type != Sketcher::Coincident) {
|
||||
if (!hasDatumLabel && type != Sketcher::Coincident && type !=InternalAlignment) {
|
||||
hasMaterial = true;
|
||||
m = dynamic_cast<SoMaterial *>(s->getChild(CONSTRAINT_SEPARATOR_INDEX_MATERIAL_OR_DATUMLABEL));
|
||||
}
|
||||
@@ -2095,9 +2145,9 @@ void ViewProviderSketch::updateColor(void)
|
||||
m->diffuseColor = SelectColor;
|
||||
} else if (type == Sketcher::Coincident) {
|
||||
int index;
|
||||
index = edit->ActSketch.getPointId(constraint->First, constraint->FirstPos) + 1;
|
||||
index = edit->ActSketch.getVisiblePointId(constraint->First, constraint->FirstPos) + 1;
|
||||
if (index >= 0 && index < PtNum) pcolor[index] = SelectColor;
|
||||
index = edit->ActSketch.getPointId(constraint->Second, constraint->SecondPos) + 1;
|
||||
index = edit->ActSketch.getVisiblePointId(constraint->Second, constraint->SecondPos) + 1;
|
||||
if (index >= 0 && index < PtNum) pcolor[index] = SelectColor;
|
||||
}
|
||||
} else if (edit->PreselectConstraintSet.count(i)) {
|
||||
@@ -2735,6 +2785,25 @@ void ViewProviderSketch::draw(bool temp)
|
||||
edit->CurvIdToGeoId.push_back(GeoId);
|
||||
Points.push_back(center);
|
||||
}
|
||||
else if ((*it)->getTypeId() == Part::GeomEllipse::getClassTypeId()) { // add an ellipse
|
||||
const Part::GeomEllipse *ellipse = dynamic_cast<const Part::GeomEllipse *>(*it);
|
||||
Handle_Geom_Ellipse curve = Handle_Geom_Ellipse::DownCast(ellipse->handle());
|
||||
|
||||
int countSegments = 50;
|
||||
Base::Vector3d center = ellipse->getCenter();
|
||||
double segment = (2 * M_PI) / countSegments;
|
||||
for (int i=0; i < countSegments; i++) {
|
||||
gp_Pnt pnt = curve->Value(i*segment);
|
||||
Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
|
||||
}
|
||||
|
||||
gp_Pnt pnt = curve->Value(0);
|
||||
Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
|
||||
|
||||
Index.push_back(countSegments+1);
|
||||
edit->CurvIdToGeoId.push_back(GeoId);
|
||||
Points.push_back(center);
|
||||
}
|
||||
else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { // add an arc
|
||||
const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(*it);
|
||||
Handle_Geom_TrimmedCurve curve = Handle_Geom_TrimmedCurve::DownCast(arc->handle());
|
||||
@@ -2768,6 +2837,39 @@ void ViewProviderSketch::draw(bool temp)
|
||||
Points.push_back(end);
|
||||
Points.push_back(center);
|
||||
}
|
||||
else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { // add an arc
|
||||
const Part::GeomArcOfEllipse *arc = dynamic_cast<const Part::GeomArcOfEllipse *>(*it);
|
||||
Handle_Geom_TrimmedCurve curve = Handle_Geom_TrimmedCurve::DownCast(arc->handle());
|
||||
|
||||
double startangle, endangle;
|
||||
arc->getRange(startangle, endangle);
|
||||
if (startangle > endangle) // if arc is reversed
|
||||
std::swap(startangle, endangle);
|
||||
|
||||
double range = endangle-startangle;
|
||||
int countSegments = std::max(6, int(50.0 * range / (2 * M_PI)));
|
||||
double segment = range / countSegments;
|
||||
|
||||
Base::Vector3d center = arc->getCenter();
|
||||
Base::Vector3d start = arc->getStartPoint();
|
||||
Base::Vector3d end = arc->getEndPoint();
|
||||
|
||||
for (int i=0; i < countSegments; i++) {
|
||||
gp_Pnt pnt = curve->Value(startangle);
|
||||
Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
|
||||
startangle += segment;
|
||||
}
|
||||
|
||||
// end point
|
||||
gp_Pnt pnt = curve->Value(endangle);
|
||||
Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
|
||||
|
||||
Index.push_back(countSegments+1);
|
||||
edit->CurvIdToGeoId.push_back(GeoId);
|
||||
Points.push_back(start);
|
||||
Points.push_back(end);
|
||||
Points.push_back(center);
|
||||
}
|
||||
else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a bspline
|
||||
const Part::GeomBSplineCurve *spline = dynamic_cast<const Part::GeomBSplineCurve *>(*it);
|
||||
Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(spline->handle());
|
||||
@@ -2875,7 +2977,8 @@ Restart:
|
||||
// root separator for this constraint
|
||||
SoSeparator *sep = dynamic_cast<SoSeparator *>(edit->constrGroup->getChild(i));
|
||||
const Constraint *Constr = *it;
|
||||
|
||||
|
||||
bool major_radius = false; // this is checked in the radius to reuse code
|
||||
// distinquish different constraint types to build up
|
||||
switch (Constr->Type) {
|
||||
case Horizontal: // write the new position of the Horizontal constraint Same as vertical position.
|
||||
@@ -2929,7 +3032,7 @@ Restart:
|
||||
norm1 = Base::Vector3d(cos(midangle),sin(midangle),0);
|
||||
dir1 = Base::Vector3d(-norm1.y,norm1.x,0);
|
||||
midpos1 = arc->getCenter() + arc->getRadius() * norm1;
|
||||
} else if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
} else if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse
|
||||
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo1);
|
||||
norm1 = Base::Vector3d(cos(M_PI/4),sin(M_PI/4),0);
|
||||
dir1 = Base::Vector3d(-norm1.y,norm1.x,0);
|
||||
@@ -2950,7 +3053,7 @@ Restart:
|
||||
norm2 = Base::Vector3d(cos(midangle),sin(midangle),0);
|
||||
dir2 = Base::Vector3d(-norm2.y,norm2.x,0);
|
||||
midpos2 = arc->getCenter() + arc->getRadius() * norm2;
|
||||
} else if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
} else if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse
|
||||
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo2);
|
||||
norm2 = Base::Vector3d(cos(M_PI/4),sin(M_PI/4),0);
|
||||
dir2 = Base::Vector3d(-norm2.y,norm2.x,0);
|
||||
@@ -2996,7 +3099,7 @@ Restart:
|
||||
geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) {
|
||||
if (Constr->Type == Equal) {
|
||||
double r1,r2,angle1,angle2;
|
||||
if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse
|
||||
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo1);
|
||||
r1 = circle->getRadius();
|
||||
angle1 = M_PI/4;
|
||||
@@ -3008,10 +3111,16 @@ Restart:
|
||||
arc->getRange(startangle, endangle);
|
||||
angle1 = (startangle + endangle)/2;
|
||||
midpos1 = arc->getCenter();
|
||||
} else if (geo1->getTypeId() == Part::GeomEllipse::getClassTypeId()) {
|
||||
// TODO: ellipse
|
||||
const Part::GeomEllipse *ellipse = dynamic_cast<const Part::GeomEllipse *>(geo1);
|
||||
r1 = ellipse->getMajorRadius();
|
||||
angle1 = -ellipse->getAngleXU();
|
||||
midpos1 = ellipse->getCenter();
|
||||
} else
|
||||
break;
|
||||
|
||||
if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse
|
||||
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo2);
|
||||
r2 = circle->getRadius();
|
||||
angle2 = M_PI/4;
|
||||
@@ -3023,7 +3132,14 @@ Restart:
|
||||
arc->getRange(startangle, endangle);
|
||||
angle2 = (startangle + endangle)/2;
|
||||
midpos2 = arc->getCenter();
|
||||
} else
|
||||
} else if (geo2->getTypeId() == Part::GeomEllipse::getClassTypeId()) {
|
||||
// TODO: ellipse
|
||||
const Part::GeomEllipse *ellipse = dynamic_cast<const Part::GeomEllipse *>(geo2);
|
||||
r2 = ellipse->getMajorRadius();
|
||||
angle2 = -ellipse->getAngleXU();
|
||||
midpos2 = ellipse->getCenter();
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
norm1 = Base::Vector3d(cos(angle1),sin(angle1),0);
|
||||
@@ -3196,7 +3312,7 @@ Restart:
|
||||
const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geo1);
|
||||
Base::Vector3d dir = (lineSeg->getEndPoint() - lineSeg->getStartPoint()).Normalize();
|
||||
Base::Vector3d norm(-dir.y, dir.x, 0);
|
||||
if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) {
|
||||
if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) { // TODO: ellipse
|
||||
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo2);
|
||||
// tangency between a line and a circle
|
||||
float length = (circle->getCenter() - lineSeg->getStartPoint())*dir;
|
||||
@@ -3204,6 +3320,24 @@ Restart:
|
||||
pos = lineSeg->getStartPoint() + dir * length;
|
||||
relPos = norm * 1; //TODO Huh?
|
||||
}
|
||||
else if (geo2->getTypeId()== Part::GeomEllipse::getClassTypeId() ||
|
||||
geo2->getTypeId()== Part::GeomArcOfEllipse::getClassTypeId()) { // TODO: ellipse
|
||||
|
||||
Base::Vector3d center;
|
||||
if(geo2->getTypeId()== Part::GeomEllipse::getClassTypeId()){
|
||||
const Part::GeomEllipse *ellipse = dynamic_cast<const Part::GeomEllipse *>(geo2);
|
||||
center=ellipse->getCenter();
|
||||
} else {
|
||||
const Part::GeomArcOfEllipse *aoc = dynamic_cast<const Part::GeomArcOfEllipse *>(geo2);
|
||||
center=aoc->getCenter();
|
||||
}
|
||||
|
||||
// tangency between a line and an ellipse
|
||||
float length = (center - lineSeg->getStartPoint())*dir;
|
||||
|
||||
pos = lineSeg->getStartPoint() + dir * length;
|
||||
relPos = norm * 1;
|
||||
}
|
||||
else if (geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) {
|
||||
const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(geo2);
|
||||
// tangency between a line and an arc
|
||||
@@ -3214,7 +3348,7 @@ Restart:
|
||||
}
|
||||
}
|
||||
|
||||
if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId() &&
|
||||
if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId() && // TODO: ellipse
|
||||
geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) {
|
||||
const Part::GeomCircle *circle1 = dynamic_cast<const Part::GeomCircle *>(geo1);
|
||||
const Part::GeomCircle *circle2 = dynamic_cast<const Part::GeomCircle *>(geo2);
|
||||
@@ -3223,12 +3357,12 @@ Restart:
|
||||
pos = circle1->getCenter() + dir * circle1->getRadius();
|
||||
relPos = dir * 1;
|
||||
}
|
||||
else if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) {
|
||||
else if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) { // TODO: ellipse
|
||||
std::swap(geo1,geo2);
|
||||
}
|
||||
|
||||
if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId() &&
|
||||
geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) {
|
||||
geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { // TODO: ellipse
|
||||
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo1);
|
||||
const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(geo2);
|
||||
// tangency between a circle and an arc
|
||||
@@ -3368,7 +3502,7 @@ Restart:
|
||||
asciiText->pnts.finishEditing();
|
||||
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case Radius:
|
||||
{
|
||||
assert(Constr->First >= -extGeoCount && Constr->First < intGeoCount);
|
||||
@@ -3386,13 +3520,14 @@ Restart:
|
||||
pnt1 = arc->getCenter();
|
||||
pnt2 = pnt1 + radius * Base::Vector3d(cos(angle),sin(angle),0.);
|
||||
}
|
||||
else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
|
||||
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo);
|
||||
double radius = circle->getRadius();
|
||||
double angle = (double) Constr->LabelPosition;
|
||||
pnt1 = circle->getCenter();
|
||||
pnt2 = pnt1 + radius * Base::Vector3d(cos(angle),sin(angle),0.);
|
||||
} else
|
||||
}
|
||||
else
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
@@ -3584,6 +3719,12 @@ void ViewProviderSketch::rebuildConstraintsVisual(void)
|
||||
edit->vConstrType.push_back((*it)->Type);
|
||||
}
|
||||
break;
|
||||
case InternalAlignment:
|
||||
{
|
||||
// TODO: Implement visual representation (if any)
|
||||
edit->vConstrType.push_back((*it)->Type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
edit->vConstrType.push_back(None);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user