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:
@@ -1793,7 +1793,580 @@ bool CmdSketcherCreateCircle::isActive(void)
|
||||
{
|
||||
return isCreateGeoActive(getActiveGuiDocument());
|
||||
}
|
||||
// ======================================================================================
|
||||
|
||||
/* XPM */
|
||||
static const char *cursor_createellipse[]={
|
||||
"32 32 3 1",
|
||||
"+ c white",
|
||||
"# c red",
|
||||
". c None",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"................................",
|
||||
"+++++...+++++...................",
|
||||
"................................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+..............#####......",
|
||||
"..................###.....#.....",
|
||||
"...............###.......##.....",
|
||||
".............##..........##.....",
|
||||
"...........##............##.....",
|
||||
"..........##.....###....##......",
|
||||
".........##.....#.#.....#.......",
|
||||
"........##.....###....##........",
|
||||
"........##...........##.........",
|
||||
".......##..........###..........",
|
||||
"......##........####............",
|
||||
"......#.....####................",
|
||||
"......######....................",
|
||||
"................................",
|
||||
"................................",
|
||||
"................................",
|
||||
"................................",
|
||||
"................................",
|
||||
"................................"};
|
||||
|
||||
class DrawSketchHandlerEllipse : public DrawSketchHandler
|
||||
{
|
||||
public:
|
||||
DrawSketchHandlerEllipse() : Mode(STATUS_SEEK_First),EditCurve(34){}
|
||||
virtual ~DrawSketchHandlerEllipse(){}
|
||||
/// mode table
|
||||
enum SelectMode {
|
||||
STATUS_SEEK_First, /**< enum value ----. */
|
||||
STATUS_SEEK_Second, /**< enum value ----. */
|
||||
STATUS_SEEK_Third, /**< enum value ----. */
|
||||
STATUS_Close
|
||||
};
|
||||
|
||||
virtual void activated(ViewProviderSketch *sketchgui)
|
||||
{
|
||||
setCursor(QPixmap(cursor_createellipse),7,7);
|
||||
}
|
||||
|
||||
virtual void mouseMove(Base::Vector2D onSketchPos)
|
||||
{
|
||||
if (Mode==STATUS_SEEK_First) {
|
||||
setPositionText(onSketchPos);
|
||||
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { // TODO: ellipse prio 1
|
||||
renderSuggestConstraintsCursor(sugConstr1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (Mode==STATUS_SEEK_Second) {
|
||||
double rx0 = onSketchPos.fX - EditCurve[0].fX;
|
||||
double ry0 = onSketchPos.fY - EditCurve[0].fY;
|
||||
for (int i=0; i < 16; i++) {
|
||||
double angle = i*M_PI/16.0;
|
||||
double rx = rx0 * cos(angle) + ry0 * sin(angle);
|
||||
double ry = -rx0 * sin(angle) + ry0 * cos(angle);
|
||||
EditCurve[1+i] = Base::Vector2D(EditCurve[0].fX + rx, EditCurve[0].fY + ry);
|
||||
EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry);
|
||||
}
|
||||
EditCurve[33] = EditCurve[1];
|
||||
|
||||
// Display radius for user
|
||||
float radius = (onSketchPos - EditCurve[0]).Length();
|
||||
|
||||
SbString text;
|
||||
text.sprintf(" (%.1fR,%.1fR)", radius,radius);
|
||||
setPositionText(onSketchPos, text);
|
||||
|
||||
sketchgui->drawEdit(EditCurve);
|
||||
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f),
|
||||
AutoConstraint::CURVE)) {
|
||||
renderSuggestConstraintsCursor(sugConstr2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (Mode==STATUS_SEEK_Third) {
|
||||
double rx0 = EditCurve[1].fX - EditCurve[0].fX; // first semidiameter
|
||||
double ry0 = EditCurve[1].fY - EditCurve[0].fY; // first semidiameter
|
||||
|
||||
// angle between the major axis of the ellipse and the X axis
|
||||
double a = (EditCurve[1]-EditCurve[0]).Length();
|
||||
double phi = atan2f(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX);
|
||||
|
||||
// This is the angle at cursor point
|
||||
double angleatpoint = acos((onSketchPos.fX-EditCurve[0].fX+(onSketchPos.fY-EditCurve[0].fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi))));
|
||||
double b=(onSketchPos.fY-EditCurve[0].fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi));
|
||||
|
||||
for (int i=1; i < 16; i++) {
|
||||
double angle = i*M_PI/16.0;
|
||||
double rx = a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi);
|
||||
double ry = a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi);
|
||||
EditCurve[1+i] = Base::Vector2D(EditCurve[0].fX + rx, EditCurve[0].fY + ry);
|
||||
EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry);
|
||||
}
|
||||
EditCurve[33] = EditCurve[1];
|
||||
EditCurve[17] = EditCurve[16];
|
||||
|
||||
// Display radius for user
|
||||
SbString text;
|
||||
text.sprintf(" (%.1fR,%.1fR)", a, b);
|
||||
setPositionText(onSketchPos, text);
|
||||
|
||||
sketchgui->drawEdit(EditCurve);
|
||||
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f),
|
||||
AutoConstraint::CURVE)) {
|
||||
renderSuggestConstraintsCursor(sugConstr2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
applyCursor();
|
||||
}
|
||||
|
||||
virtual bool pressButton(Base::Vector2D onSketchPos)
|
||||
{
|
||||
if (Mode==STATUS_SEEK_First){
|
||||
EditCurve[0] = onSketchPos;
|
||||
Mode = STATUS_SEEK_Second;
|
||||
}
|
||||
else if(Mode==STATUS_SEEK_Second) {
|
||||
EditCurve[1] = onSketchPos;
|
||||
Mode = STATUS_SEEK_Third;
|
||||
}
|
||||
else {
|
||||
EditCurve[2] = onSketchPos;
|
||||
Mode = STATUS_Close;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool releaseButton(Base::Vector2D onSketchPos)
|
||||
{
|
||||
if (Mode==STATUS_Close) {
|
||||
unsetCursor();
|
||||
resetPositionText();
|
||||
|
||||
// angle between the major axis of the ellipse and the X axis
|
||||
double a = (EditCurve[1]-EditCurve[0]).Length();
|
||||
double phi = atan2f(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX);
|
||||
|
||||
// This is the angle at cursor point
|
||||
double angleatpoint = acos((EditCurve[2].fX-EditCurve[0].fX+(EditCurve[2].fY-EditCurve[0].fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi))));
|
||||
double b=(EditCurve[2].fY-EditCurve[0].fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi));
|
||||
|
||||
Base::Vector2D majAxisDir,minAxisDir,minAxisPoint,majAxisPoint;
|
||||
// We always create a CCW ellipse, because we want our XY reference system to be in the +X +Y direction
|
||||
// Our normal will then always be in the +Z axis (local +Z axis of the sketcher)
|
||||
|
||||
if(a>b)
|
||||
{
|
||||
// force second semidiameter to be perpendicular to first semidiamater
|
||||
majAxisDir = EditCurve[1] - EditCurve[0];
|
||||
Base::Vector2D perp(-majAxisDir.fY,majAxisDir.fX);
|
||||
perp.Normalize();
|
||||
perp.Scale(abs(b));
|
||||
minAxisPoint = EditCurve[0]+perp;
|
||||
majAxisPoint = EditCurve[0]+majAxisDir;
|
||||
}
|
||||
else {
|
||||
// force second semidiameter to be perpendicular to first semidiamater
|
||||
minAxisDir = EditCurve[1] - EditCurve[0];
|
||||
Base::Vector2D perp(minAxisDir.fY,-minAxisDir.fX);
|
||||
perp.Normalize();
|
||||
perp.Scale(abs(b));
|
||||
majAxisPoint = EditCurve[0]+perp;
|
||||
minAxisPoint = EditCurve[0]+minAxisDir;
|
||||
}
|
||||
|
||||
Gui::Command::openCommand("Add sketch ellipse");
|
||||
Gui::Command::doCommand(Gui::Command::Doc,
|
||||
"App.ActiveDocument.%s.addGeometry(Part.Ellipse"
|
||||
"(App.Vector(%f,%f,0),App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
|
||||
sketchgui->getObject()->getNameInDocument(),
|
||||
majAxisPoint.fX, majAxisPoint.fY,
|
||||
minAxisPoint.fX, minAxisPoint.fY,
|
||||
EditCurve[0].fX, EditCurve[0].fY);
|
||||
|
||||
Gui::Command::commitCommand();
|
||||
Gui::Command::updateActive();
|
||||
|
||||
// add auto constraints for the center point
|
||||
if (sugConstr1.size() > 0) {
|
||||
createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::mid);
|
||||
sugConstr1.clear();
|
||||
}
|
||||
|
||||
// add suggested constraints for circumference
|
||||
if (sugConstr2.size() > 0) {
|
||||
//createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::none);
|
||||
sugConstr2.clear();
|
||||
}
|
||||
|
||||
EditCurve.clear();
|
||||
sketchgui->drawEdit(EditCurve);
|
||||
sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider
|
||||
}
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
SelectMode Mode;
|
||||
std::vector<Base::Vector2D> EditCurve;
|
||||
std::vector<AutoConstraint> sugConstr1, sugConstr2;
|
||||
|
||||
};
|
||||
|
||||
DEF_STD_CMD_A(CmdSketcherCreateEllipse);
|
||||
|
||||
CmdSketcherCreateEllipse::CmdSketcherCreateEllipse()
|
||||
: Command("Sketcher_CreateEllipse")
|
||||
{
|
||||
sAppModule = "Sketcher";
|
||||
sGroup = QT_TR_NOOP("Sketcher");
|
||||
sMenuText = QT_TR_NOOP("Create ellipse");
|
||||
sToolTipText = QT_TR_NOOP("Create an ellipse in the sketch");
|
||||
sWhatsThis = sToolTipText;
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Sketcher_CreateEllipse";
|
||||
eType = ForEdit;
|
||||
}
|
||||
|
||||
void CmdSketcherCreateEllipse::activated(int iMsg)
|
||||
{
|
||||
ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerEllipse() );
|
||||
}
|
||||
|
||||
bool CmdSketcherCreateEllipse::isActive(void)
|
||||
{
|
||||
return isCreateGeoActive(getActiveGuiDocument());
|
||||
}
|
||||
|
||||
// ======================================================================================
|
||||
|
||||
/* XPM */
|
||||
static const char *cursor_createarcofellipse[]={
|
||||
"32 32 3 1",
|
||||
"+ c white",
|
||||
"# c red",
|
||||
". c None",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"................................",
|
||||
"+++++...+++++...................",
|
||||
"................................",
|
||||
"......+.........................",
|
||||
"......+.........................",
|
||||
"......+................##.......",
|
||||
"......+..............##.........",
|
||||
"......+............##...........",
|
||||
"......+...........##............",
|
||||
"................##..............",
|
||||
"...............##...............",
|
||||
"..............##................",
|
||||
".............###................",
|
||||
"............##.........###......",
|
||||
"...........##.........#.#.......",
|
||||
"...........##.........###.......",
|
||||
"..........##....................",
|
||||
".........##.....................",
|
||||
"........##......................",
|
||||
"........##......................",
|
||||
"........##......................",
|
||||
"........#.....####..............",
|
||||
"........######..................",
|
||||
"................................",
|
||||
"................................",
|
||||
"................................",
|
||||
"................................"};
|
||||
|
||||
class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler
|
||||
{
|
||||
public:
|
||||
DrawSketchHandlerArcOfEllipse() : Mode(STATUS_SEEK_First),EditCurve(34){}
|
||||
virtual ~DrawSketchHandlerArcOfEllipse(){}
|
||||
/// mode table
|
||||
enum SelectMode {
|
||||
STATUS_SEEK_First, /**< enum value ----. */
|
||||
STATUS_SEEK_Second, /**< enum value ----. */
|
||||
STATUS_SEEK_Third, /**< enum value ----. */
|
||||
STATUS_SEEK_Fourth, /**< enum value ----. */
|
||||
STATUS_Close
|
||||
};
|
||||
|
||||
virtual void activated(ViewProviderSketch *sketchgui)
|
||||
{
|
||||
setCursor(QPixmap(cursor_createarcofellipse),7,7);
|
||||
}
|
||||
|
||||
virtual void mouseMove(Base::Vector2D onSketchPos)
|
||||
{
|
||||
if (Mode==STATUS_SEEK_First) {
|
||||
setPositionText(onSketchPos);
|
||||
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { // TODO: ellipse prio 1
|
||||
renderSuggestConstraintsCursor(sugConstr1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (Mode==STATUS_SEEK_Second) {
|
||||
double rx0 = onSketchPos.fX - EditCurve[0].fX;
|
||||
double ry0 = onSketchPos.fY - EditCurve[0].fY;
|
||||
for (int i=0; i < 16; i++) {
|
||||
double angle = i*M_PI/16.0;
|
||||
double rx = rx0 * cos(angle) + ry0 * sin(angle);
|
||||
double ry = -rx0 * sin(angle) + ry0 * cos(angle);
|
||||
EditCurve[1+i] = Base::Vector2D(EditCurve[0].fX + rx, EditCurve[0].fY + ry);
|
||||
EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry);
|
||||
}
|
||||
EditCurve[33] = EditCurve[1];
|
||||
|
||||
// Display radius for user
|
||||
float radius = (onSketchPos - EditCurve[0]).Length();
|
||||
|
||||
SbString text;
|
||||
text.sprintf(" (%.1fR,%.1fR)", radius,radius);
|
||||
setPositionText(onSketchPos, text);
|
||||
|
||||
sketchgui->drawEdit(EditCurve);
|
||||
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f),
|
||||
AutoConstraint::CURVE)) {
|
||||
renderSuggestConstraintsCursor(sugConstr2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (Mode==STATUS_SEEK_Third) {
|
||||
double rx0 = EditCurve[1].fX - EditCurve[0].fX; // first semidiameter
|
||||
double ry0 = EditCurve[1].fY - EditCurve[0].fY; // first semidiameter
|
||||
|
||||
// angle between the major axis of the ellipse and the X axis
|
||||
double a = (EditCurve[1]-EditCurve[0]).Length();
|
||||
double phi = atan2f(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX);
|
||||
|
||||
// This is the angle at cursor point
|
||||
double angleatpoint = acos((onSketchPos.fX-EditCurve[0].fX+(onSketchPos.fY-EditCurve[0].fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi))));
|
||||
double b=(onSketchPos.fY-EditCurve[0].fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi));
|
||||
|
||||
for (int i=1; i < 16; i++) {
|
||||
double angle = i*M_PI/16.0;
|
||||
double rx = a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi);
|
||||
double ry = a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi);
|
||||
EditCurve[1+i] = Base::Vector2D(EditCurve[0].fX + rx, EditCurve[0].fY + ry);
|
||||
EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry);
|
||||
}
|
||||
EditCurve[33] = EditCurve[1];
|
||||
EditCurve[17] = EditCurve[16];
|
||||
|
||||
// Display radius for user
|
||||
SbString text;
|
||||
text.sprintf(" (%.1fR,%.1fR)", a, b);
|
||||
setPositionText(onSketchPos, text);
|
||||
|
||||
sketchgui->drawEdit(EditCurve);
|
||||
if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f),
|
||||
AutoConstraint::CURVE)) {
|
||||
renderSuggestConstraintsCursor(sugConstr3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (Mode==STATUS_SEEK_Fourth) { // here we differ from ellipse creation
|
||||
|
||||
double rx0 = axisPoint.fX - centerPoint.fX; // first semidiameter
|
||||
double ry0 = axisPoint.fY - centerPoint.fY; // first semidiameter
|
||||
|
||||
// angle between the major axis of the ellipse and the X axis
|
||||
double a = (axisPoint-centerPoint).Length();
|
||||
double phi = atan2(axisPoint.fY-centerPoint.fY,axisPoint.fX-centerPoint.fX);
|
||||
|
||||
// This is the angle at cursor point
|
||||
double angleatpoint = acos((startingPoint.fX-centerPoint.fX+(startingPoint.fY-centerPoint.fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi))));
|
||||
double b=abs((startingPoint.fY-centerPoint.fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi)));
|
||||
|
||||
double rxs = startingPoint.fX - centerPoint.fX;
|
||||
double rys = startingPoint.fY - centerPoint.fY;
|
||||
startAngle = atan2(a*(rys*cos(phi)-rxs*sin(phi)), b*(rxs*cos(phi)+rys*sin(phi))); // eccentric anomaly angle
|
||||
|
||||
double angle1 = atan2(a*((onSketchPos.fY - centerPoint.fY)*cos(phi)-(onSketchPos.fX - centerPoint.fX)*sin(phi)),
|
||||
b*((onSketchPos.fX - centerPoint.fX)*cos(phi)+(onSketchPos.fY - centerPoint.fY)*sin(phi)))- startAngle;
|
||||
|
||||
double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ;
|
||||
arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;
|
||||
|
||||
for (int i=0; i < 34; i++) {
|
||||
double angle = startAngle+i*arcAngle/34.0;
|
||||
double rx = a * cos(angle) * cos(phi) - b * sin(angle) * sin(phi);
|
||||
double ry = a * cos(angle) * sin(phi) + b * sin(angle) * cos(phi);
|
||||
EditCurve[i] = Base::Vector2D(centerPoint.fX + rx, centerPoint.fY + ry);
|
||||
}
|
||||
// EditCurve[33] = EditCurve[1];
|
||||
// EditCurve[17] = EditCurve[16];
|
||||
|
||||
// Display radii and angle for user
|
||||
SbString text;
|
||||
text.sprintf(" (%.1fR,%.1fR,%.1fdeg)", a, b, arcAngle * 180 / M_PI);
|
||||
setPositionText(onSketchPos, text);
|
||||
|
||||
sketchgui->drawEdit(EditCurve);
|
||||
if (seekAutoConstraint(sugConstr4, onSketchPos, Base::Vector2D(0.f,0.f),
|
||||
AutoConstraint::CURVE)) {
|
||||
renderSuggestConstraintsCursor(sugConstr4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
applyCursor();
|
||||
}
|
||||
|
||||
virtual bool pressButton(Base::Vector2D onSketchPos)
|
||||
{
|
||||
if (Mode==STATUS_SEEK_First){
|
||||
EditCurve[0] = onSketchPos;
|
||||
centerPoint = onSketchPos;
|
||||
Mode = STATUS_SEEK_Second;
|
||||
}
|
||||
else if(Mode==STATUS_SEEK_Second) {
|
||||
EditCurve[1] = onSketchPos;
|
||||
axisPoint = onSketchPos;
|
||||
Mode = STATUS_SEEK_Third;
|
||||
}
|
||||
else if(Mode==STATUS_SEEK_Third) {
|
||||
startingPoint = onSketchPos;
|
||||
arcAngle = 0.;
|
||||
arcAngle_t= 0.;
|
||||
Mode = STATUS_SEEK_Fourth;
|
||||
}
|
||||
else { // Fourth
|
||||
endPoint = onSketchPos;
|
||||
|
||||
Mode = STATUS_Close;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool releaseButton(Base::Vector2D onSketchPos)
|
||||
{
|
||||
if (Mode==STATUS_Close) {
|
||||
unsetCursor();
|
||||
resetPositionText();
|
||||
|
||||
// angle between the major axis of the ellipse and the X axis
|
||||
double a = (axisPoint-centerPoint).Length();
|
||||
double phi = atan2(axisPoint.fY-centerPoint.fY,axisPoint.fX-centerPoint.fX);
|
||||
|
||||
// This is the angle at cursor point
|
||||
double angleatpoint = acos((startingPoint.fX-centerPoint.fX+(startingPoint.fY-centerPoint.fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi))));
|
||||
double b=abs((startingPoint.fY-centerPoint.fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi)));
|
||||
|
||||
double angle1 = atan2(a*((endPoint.fY - centerPoint.fY)*cos(phi)-(endPoint.fX - centerPoint.fX)*sin(phi)),
|
||||
b*((endPoint.fX - centerPoint.fX)*cos(phi)+(endPoint.fY - centerPoint.fY)*sin(phi)))- startAngle;
|
||||
|
||||
double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ;
|
||||
arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;
|
||||
|
||||
if (arcAngle > 0)
|
||||
endAngle = startAngle + arcAngle;
|
||||
else {
|
||||
endAngle = startAngle;
|
||||
startAngle += arcAngle;
|
||||
}
|
||||
|
||||
Base::Vector2D majAxisDir,minAxisDir,minAxisPoint,majAxisPoint;
|
||||
// We always create a CCW ellipse, because we want our XY reference system to be in the +X +Y direction
|
||||
// Our normal will then always be in the +Z axis (local +Z axis of the sketcher)
|
||||
|
||||
if(a>b)
|
||||
{
|
||||
// force second semidiameter to be perpendicular to first semidiamater
|
||||
majAxisDir = axisPoint - centerPoint;
|
||||
Base::Vector2D perp(-majAxisDir.fY,majAxisDir.fX);
|
||||
perp.Normalize();
|
||||
perp.Scale(abs(b));
|
||||
minAxisPoint = centerPoint+perp;
|
||||
majAxisPoint = centerPoint+majAxisDir;
|
||||
}
|
||||
else {
|
||||
// force second semidiameter to be perpendicular to first semidiamater
|
||||
minAxisDir = axisPoint - centerPoint;
|
||||
Base::Vector2D perp(minAxisDir.fY,-minAxisDir.fX);
|
||||
perp.Normalize();
|
||||
perp.Scale(abs(b));
|
||||
majAxisPoint = centerPoint+perp;
|
||||
minAxisPoint = centerPoint+minAxisDir;
|
||||
endAngle += M_PI/2;
|
||||
startAngle += M_PI/2;
|
||||
}
|
||||
|
||||
//startAngle=-M_PI/4;
|
||||
//endAngle=M_PI/4;
|
||||
|
||||
Gui::Command::openCommand("Add sketch arc of ellipse");
|
||||
Gui::Command::doCommand(Gui::Command::Doc,
|
||||
"App.ActiveDocument.%s.addGeometry(Part.ArcOfEllipse"
|
||||
"(Part.Ellipse(App.Vector(%f,%f,0),App.Vector(%f,%f,0),App.Vector(%f,%f,0)),"
|
||||
"%f,%f))",
|
||||
sketchgui->getObject()->getNameInDocument(),
|
||||
majAxisPoint.fX, majAxisPoint.fY,
|
||||
minAxisPoint.fX, minAxisPoint.fY,
|
||||
centerPoint.fX, centerPoint.fY,
|
||||
startAngle, endAngle); //arcAngle > 0 ? 0 : 1);
|
||||
|
||||
Gui::Command::commitCommand();
|
||||
Gui::Command::updateActive();
|
||||
|
||||
// add auto constraints for the center point
|
||||
if (sugConstr1.size() > 0) {
|
||||
createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::mid);
|
||||
sugConstr1.clear();
|
||||
}
|
||||
|
||||
// add suggested constraints for circumference
|
||||
if (sugConstr2.size() > 0) {
|
||||
//createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::none);
|
||||
sugConstr2.clear();
|
||||
}
|
||||
|
||||
EditCurve.clear();
|
||||
sketchgui->drawEdit(EditCurve);
|
||||
sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider
|
||||
}
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
SelectMode Mode;
|
||||
std::vector<Base::Vector2D> EditCurve;
|
||||
Base::Vector2D centerPoint, axisPoint, startingPoint, endPoint;
|
||||
double rx, ry, startAngle, endAngle, arcAngle, arcAngle_t;
|
||||
std::vector<AutoConstraint> sugConstr1, sugConstr2, sugConstr3, sugConstr4;
|
||||
|
||||
};
|
||||
|
||||
DEF_STD_CMD_A(CmdSketcherCreateArcOfEllipse);
|
||||
|
||||
CmdSketcherCreateArcOfEllipse::CmdSketcherCreateArcOfEllipse()
|
||||
: Command("Sketcher_CreateArcOfEllipse")
|
||||
{
|
||||
sAppModule = "Sketcher";
|
||||
sGroup = QT_TR_NOOP("Sketcher");
|
||||
sMenuText = QT_TR_NOOP("Create an arc of ellipse");
|
||||
sToolTipText = QT_TR_NOOP("Create an arc of ellipse in the sketch");
|
||||
sWhatsThis = sToolTipText;
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Sketcher_Elliptical_Arc";
|
||||
eType = ForEdit;
|
||||
}
|
||||
|
||||
void CmdSketcherCreateArcOfEllipse::activated(int iMsg)
|
||||
{
|
||||
ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerArcOfEllipse() );
|
||||
}
|
||||
|
||||
bool CmdSketcherCreateArcOfEllipse::isActive(void)
|
||||
{
|
||||
return isCreateGeoActive(getActiveGuiDocument());
|
||||
}
|
||||
|
||||
// ======================================================================================
|
||||
|
||||
@@ -2548,6 +3121,7 @@ namespace SketcherGui {
|
||||
geom->getTypeId() == Part::GeomCircle::getClassTypeId()||
|
||||
geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
|
||||
return true;
|
||||
// TODO: ellipse
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2628,6 +3202,7 @@ public:
|
||||
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomCircle::getClassTypeId()
|
||||
// TODO: ellipse
|
||||
) {
|
||||
try {
|
||||
Gui::Command::openCommand("Trim edge");
|
||||
@@ -3548,6 +4123,8 @@ void CreateSketcherCommandsCreateGeo(void)
|
||||
rcCmdMgr.addCommand(new CmdSketcherCreateCircle());
|
||||
rcCmdMgr.addCommand(new CmdSketcherCreate3PointCircle());
|
||||
rcCmdMgr.addCommand(new CmdSketcherCompCreateCircle());
|
||||
rcCmdMgr.addCommand(new CmdSketcherCreateEllipse());
|
||||
rcCmdMgr.addCommand(new CmdSketcherCreateArcOfEllipse());
|
||||
rcCmdMgr.addCommand(new CmdSketcherCreateLine());
|
||||
rcCmdMgr.addCommand(new CmdSketcherCreatePolyline());
|
||||
rcCmdMgr.addCommand(new CmdSketcherCreateRectangle());
|
||||
|
||||
Reference in New Issue
Block a user