Sketcher: Ellipse implementation enhancements

- ArcOfEllipse enhancement: Tangency ArcOfEllipse to ArcOfEllipse or ArcOfCircle by selecting end/starting points...
- Minor bug corrections (Thanks DeepSOIC)
- ExposeInternalGeometry python command
- DeleteUnusedInternalGeometry python command
- On deletion of an Ellipse/ArcOfEllipse all further unconstrained internal geometry is also deleted.
- This cleans up the code by eliminating code repetition in the creation methods.
- Major bug fix for autoconstraints for ellipse and arc of ellipse creation (for both creation methods)
- Major bug fix Start and Endpoint constraints of an arc of ellipse where not taking into account that Sketcher arcs are always CCW, so they have to be exchanged if we convert a CW arc into a CCW arc.

Sketcher: General bug fix: Tangency wrongly suggested

What?
=====
- On creation of a shape autoconstraints are suggested.
- Tangent autoconstraint was suggested even with lines perpendicular to the tangency direction

Reproduce
=========
- Make a circle on the origin and move the mouse along the X axis, it will suggest a tangency that is impossible
- Click on the axis and no circle will be created

Solution
========
- The SeekConstraint now can use the parameter dir to give a direction that is substantially perpendicular to the expected tangency, so that
if an object having a direction (a line) is hit, a tangency will not be suggested if within around 6 degrees of being parallel.
- Additionally, if such a line is an X,Y axis of the sketch, tangency will only be suggested if the direction is within 6 degrees of being perpendicular (i.e. it is almost tangent already while sketching).
- This difference is due to the fact that an X or Y axis can not "move" to meet the object under creation, whereas a line can.
This commit is contained in:
Abdullah Tahiri
2014-11-01 15:12:18 +01:00
committed by wmayer
parent d1e3fa4815
commit d3b0cf771f
10 changed files with 846 additions and 282 deletions

View File

@@ -2307,7 +2307,7 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine)
GCS::Point &center = Points[Geoms[geoId].midPointId];
GCS::Point p0,p1;
if (pos == mid | pos == none) {
if (pos == mid || pos == none) {
MoveParameters.resize(2); // cx,cy
p0.x = &MoveParameters[0];
p0.y = &MoveParameters[1];

View File

@@ -355,6 +355,8 @@ int SketchObject::delGeometry(int GeoId)
if (GeoId < 0 || GeoId >= int(vals.size()))
return -1;
this->DeleteUnusedInternalGeometry(GeoId);
std::vector< Part::Geometry * > newVals(vals);
newVals.erase(newVals.begin()+GeoId);
@@ -1358,17 +1360,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
delConstraintOnPoint(GeoId, end, false);
Part::GeomArcOfEllipse *aoe1 = dynamic_cast<Part::GeomArcOfEllipse*>(geomlist[GeoId]);
aoe1->setRange(startAngle, startAngle + theta1);
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
newConstr->Type = constrType;
newConstr->First = GeoId;
newConstr->FirstPos = end;
newConstr->Second = GeoId1;
if (constrType == Sketcher::Coincident)
newConstr->SecondPos = secondPos;
addConstraint(newConstr);
delete newConstr;
return 0;
}
}
@@ -1378,6 +1370,264 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
return -1;
}
int SketchObject::ExposeInternalGeometry(int GeoId)
{
if (GeoId < 0 || GeoId > getHighestCurveIndex())
return -1;
const Part::Geometry *geo = getGeometry(GeoId);
// Only for supported types
if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) {
// First we search what has to be restored
bool major=false;
bool minor=false;
bool focus1=false;
bool focus2=false;
int majorelementindex=-1;
int minorelementindex=-1;
int focus1elementindex=-1;
int focus2elementindex=-1;
const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues();
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();
it != vals.end(); ++it) {
if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId)
{
switch((*it)->AlignmentType){
case Sketcher::EllipseMajorDiameter:
major=true;
majorelementindex=(*it)->First;
break;
case Sketcher::EllipseMinorDiameter:
minor=true;
minorelementindex=(*it)->First;
break;
case Sketcher::EllipseFocus1:
focus1=true;
focus1elementindex=(*it)->First;
break;
case Sketcher::EllipseFocus2:
focus2=true;
focus2elementindex=(*it)->First;
break;
}
}
}
int currentgeoid= getHighestCurveIndex();
int incrgeo= 0;
Base::Vector3d center;
double majord;
double minord;
double phi;
if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId()){
const Part::GeomEllipse *ellipse = static_cast<const Part::GeomEllipse *>(geo);
center=ellipse->getCenter();
majord=ellipse->getMajorRadius();
minord=ellipse->getMinorRadius();
phi=ellipse->getAngleXU();
}
else {
const Part::GeomArcOfEllipse *aoe = static_cast<const Part::GeomArcOfEllipse *>(geo);
center=aoe->getCenter();
majord=aoe->getMajorRadius();
minord=aoe->getMinorRadius();
phi=aoe->getAngleXU();
}
Base::Vector3d majorpositiveend = center + majord * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d majornegativeend = center - majord * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d minorpositiveend = center + minord * Base::Vector3d(-sin(phi),cos(phi),0);
Base::Vector3d minornegativeend = center - minord * Base::Vector3d(-sin(phi),cos(phi),0);
double df= sqrt(majord*majord-minord*minord);
Base::Vector3d focus1P = center + df * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d focus2P = center - df * Base::Vector3d(cos(phi),sin(phi),0);
if(!major)
{
Part::GeomLineSegment *lmajor = new Part::GeomLineSegment();
lmajor->setPoints(majorpositiveend,majornegativeend);
this->addGeometry(lmajor); // create line for major axis
this->setConstruction(currentgeoid+incrgeo+1,true);
delete lmajor;
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
newConstr->Type = Sketcher::InternalAlignment;
newConstr->AlignmentType = EllipseMajorDiameter;
newConstr->First = currentgeoid+incrgeo+1;
newConstr->Second = GeoId;
addConstraint(newConstr);
delete newConstr;
incrgeo++;
}
if(!minor)
{
Part::GeomLineSegment *lminor = new Part::GeomLineSegment();
lminor->setPoints(minorpositiveend,minornegativeend);
this->addGeometry(lminor); // create line for major axis
this->setConstruction(currentgeoid+incrgeo+1,true);
delete lminor;
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
newConstr->Type = Sketcher::InternalAlignment;
newConstr->AlignmentType = EllipseMinorDiameter;
newConstr->First = currentgeoid+incrgeo+1;
newConstr->Second = GeoId;
addConstraint(newConstr);
delete newConstr;
incrgeo++;
}
if(!focus1)
{
Part::GeomPoint *pf1 = new Part::GeomPoint();
pf1->setPoint(focus1P);
this->addGeometry(pf1);
delete pf1;
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
newConstr->Type = Sketcher::InternalAlignment;
newConstr->AlignmentType = EllipseFocus1;
newConstr->First = currentgeoid+incrgeo+1;
newConstr->FirstPos = Sketcher::start;
newConstr->Second = GeoId;
addConstraint(newConstr);
delete newConstr;
incrgeo++;
}
if(!focus2)
{
Part::GeomPoint *pf2 = new Part::GeomPoint();
pf2->setPoint(focus2P);
this->addGeometry(pf2);
delete pf2;
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
newConstr->Type = Sketcher::InternalAlignment;
newConstr->AlignmentType = EllipseFocus2;
newConstr->First = currentgeoid+incrgeo+1;
newConstr->FirstPos = Sketcher::start;
newConstr->Second = GeoId;
addConstraint(newConstr);
delete newConstr;
}
return incrgeo; //number of added elements
}
else
return -1; // not supported type
}
int SketchObject::DeleteUnusedInternalGeometry(int GeoId)
{
if (GeoId < 0 || GeoId > getHighestCurveIndex())
return -1;
const Part::Geometry *geo = getGeometry(GeoId);
// Only for supported types
if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) {
// First we search what has to be deleted
bool major=false;
bool minor=false;
bool focus1=false;
bool focus2=false;
int majorelementindex=-1;
int minorelementindex=-1;
int focus1elementindex=-1;
int focus2elementindex=-1;
const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues();
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();
it != vals.end(); ++it) {
if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId)
{
switch((*it)->AlignmentType){
case Sketcher::EllipseMajorDiameter:
major=true;
majorelementindex=(*it)->First;
break;
case Sketcher::EllipseMinorDiameter:
minor=true;
minorelementindex=(*it)->First;
break;
case Sketcher::EllipseFocus1:
focus1=true;
focus1elementindex=(*it)->First;
break;
case Sketcher::EllipseFocus2:
focus2=true;
focus2elementindex=(*it)->First;
break;
}
}
}
// Hide unused geometry here
int majorconstraints=0; // number of constraints associated to the geoid of the major axis
int minorconstraints=0;
int focus1constraints=0;
int focus2constraints=0;
int decrgeo=0;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();
it != vals.end(); ++it) {
if((*it)->Second == majorelementindex || (*it)->First == majorelementindex || (*it)->Third == majorelementindex)
majorconstraints++;
else if((*it)->Second == minorelementindex || (*it)->First == minorelementindex || (*it)->Third == minorelementindex)
minorconstraints++;
else if((*it)->Second == focus1elementindex || (*it)->First == focus1elementindex || (*it)->Third == focus1elementindex)
focus1constraints++;
else if((*it)->Second == focus2elementindex || (*it)->First == focus2elementindex || (*it)->Third == focus2elementindex)
focus2constraints++;
}
std::vector<int> delgeometries;
// those with less than 2 constraints must be removed
if(focus2constraints<2)
delgeometries.push_back(focus2elementindex);
if(focus1constraints<2)
delgeometries.push_back(focus1elementindex);
if(minorconstraints<2)
delgeometries.push_back(minorelementindex);
if(majorconstraints<2)
delgeometries.push_back(majorelementindex);
std::sort(delgeometries.begin(), delgeometries.end()); // indices over an erased element get automatically updated!!
if(delgeometries.size()>0)
{
for (std::vector<int>::reverse_iterator it=delgeometries.rbegin(); it!=delgeometries.rend(); ++it) {
delGeometry(*it);
}
}
return delgeometries.size(); //number of deleted elements
}
else
return -1; // not supported type
}
int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName)
{
// so far only externals to the support of the sketch

View File

@@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2008 *
* Copyright (c) J<EFBFBD>rgen Riegel (juergen.riegel@web.de) 2008 *
* *
* This file is part of the FreeCAD CAx development system. *
* *
@@ -47,6 +47,7 @@ public:
Part ::PropertyGeometryList Geometry;
Sketcher::PropertyConstraintList Constraints;
App ::PropertyLinkSubList ExternalGeometry;
const char* ss;
/** @name methods overide Feature */
//@{
/// recalculate the Feature
@@ -127,6 +128,10 @@ public:
/// trim a curve
int trim(int geoId, const Base::Vector3d& point);
/// Exposes all internal geometry of an object supporting internal geometry
int ExposeInternalGeometry(int GeoId);
/// Deletes all unused (not further constrained) internal geometry
int DeleteUnusedInternalGeometry(int GeoId);
/// retrieves for a Vertex number the corresponding GeoId and PosId
void getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId) const;
@@ -158,6 +163,7 @@ public:
virtual int getAxisCount(void) const;
/// retrieves an axis iterating through the construction lines of the sketch (indices start at 0)
virtual Base::Axis getAxis(int axId) const;
const char*& it(int arg1, int arg2);
protected:
/// get called by the container when a property has changed

View File

@@ -112,6 +112,16 @@
<UserDocu>trim a curve with a given id at a given reference point</UserDocu>
</Documentation>
</Methode>
<Methode Name="ExposeInternalGeometry">
<Documentation>
<UserDocu>Exposes all internal geometry of an object supporting internal geometry</UserDocu>
</Documentation>
</Methode>
<Methode Name="DeleteUnusedInternalGeometry">
<Documentation>
<UserDocu>Deletes all unused (not further constrained) internal geometry</UserDocu>
</Documentation>
</Methode>
<Attribute Name="ConstraintCount" ReadOnly="true">
<Documentation>
<UserDocu>Number of Constraints in this sketch</UserDocu>

View File

@@ -596,6 +596,40 @@ PyObject* SketchObjectPy::trim(PyObject *args)
}
PyObject* SketchObjectPy::ExposeInternalGeometry(PyObject *args)
{
int GeoId;
if (!PyArg_ParseTuple(args, "i", &GeoId))
return 0;
if (this->getSketchObjectPtr()->ExposeInternalGeometry(GeoId)==-1) {
std::stringstream str;
str << "Object does not support internal geometry: " << GeoId;
PyErr_SetString(PyExc_ValueError, str.str().c_str());
return 0;
}
Py_Return;
}
PyObject* SketchObjectPy::DeleteUnusedInternalGeometry(PyObject *args)
{
int GeoId;
if (!PyArg_ParseTuple(args, "i", &GeoId))
return 0;
if (this->getSketchObjectPtr()->DeleteUnusedInternalGeometry(GeoId)==-1) {
std::stringstream str;
str << "Object does not support internal geometry: " << GeoId;
PyErr_SetString(PyExc_ValueError, str.str().c_str());
return 0;
}
Py_Return;
}
Py::Int SketchObjectPy::getConstraintCount(void) const
{
return Py::Int(this->getSketchObjectPtr()->Constraints.getSize());

View File

@@ -62,6 +62,7 @@ SET(SketcherGui_SRCS
AppSketcherGuiPy.cpp
Command.cpp
CommandCreateGeo.cpp
CommandConstraints.h
CommandConstraints.cpp
CommandSketcherTools.cpp
CommandAlterGeometry.cpp

View File

@@ -42,6 +42,7 @@
#include "ViewProviderSketch.h"
#include "ui_InsertDatum.h"
#include "EditDatumDialog.h"
#include "CommandConstraints.h"
using namespace std;
using namespace SketcherGui;
@@ -154,6 +155,162 @@ bool isSimpleVertex(const Sketcher::SketchObject* Obj, int GeoId, PointPos PosId
return false;
}
/// Makes a tangency constraint using external construction line between
/// geom1 => an ellipse
/// geom2 => any of an ellipse, an arc of ellipse, a circle, or an arc (of circle)
/// NOTE: A command must be opened before calling this function, which this function
/// commits or aborts as appropriate. The reason is for compatibility reasons with
/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp
void SketcherGui::makeTangentToEllipseviaConstructionLine(const Sketcher::SketchObject* Obj,
const Part::Geometry *geom1,
const Part::Geometry *geom2,
int geoId1,
int geoId2
)
{
const Part::GeomEllipse *ellipse = static_cast<const Part::GeomEllipse *>(geom1);
Base::Vector3d center=ellipse->getCenter();
double majord=ellipse->getMajorRadius();
double minord=ellipse->getMinorRadius();
double phi=ellipse->getAngleXU();
Base::Vector3d center2;
if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() )
center2= (static_cast<const Part::GeomEllipse *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfEllipse *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId())
center2= (static_cast<const Part::GeomCircle *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfCircle *>(geom2))->getCenter();
Base::Vector3d direction=center2-center;
double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar
Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi),
center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0);
Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x);
Base::Vector3d endpoint = PoE+perp;
int currentgeoid= Obj->getHighestCurveIndex();
try {
// Add a construction line
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
Obj->getNameInDocument(),
PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1);
// Point on first object
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
Obj->getNameInDocument(),currentgeoid+1,Sketcher::start,geoId1); // constrain major axis
// Point on second object
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
Obj->getNameInDocument(),currentgeoid+1,Sketcher::start,geoId2); // constrain major axis
// tangent to first object
Gui::Command::doCommand(
Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
Obj->getNameInDocument(),currentgeoid+1,geoId1);
// tangent to second object
Gui::Command::doCommand(
Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
Obj->getNameInDocument(),currentgeoid+1,geoId2);
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
Gui::Command::abortCommand();
Gui::Command::updateActive();
return;
}
Gui::Command::commitCommand();
Gui::Command::updateActive();
}
/// Makes a tangency constraint using external construction line between
/// geom1 => an arc of ellipse
/// geom2 => any of an arc of ellipse, a circle, or an arc (of circle)
/// NOTE: A command must be opened before calling this function, which this function
/// commits or aborts as appropriate. The reason is for compatibility reasons with
/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp
void SketcherGui::makeTangentToArcOfEllipseviaConstructionLine(const Sketcher::SketchObject* Obj,
const Part::Geometry *geom1,
const Part::Geometry *geom2,
int geoId1,
int geoId2
)
{
const Part::GeomArcOfEllipse *aoe = static_cast<const Part::GeomArcOfEllipse *>(geom1);
Base::Vector3d center=aoe->getCenter();
double majord=aoe->getMajorRadius();
double minord=aoe->getMinorRadius();
double phi=aoe->getAngleXU();
Base::Vector3d center2;
if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfEllipse *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId())
center2= (static_cast<const Part::GeomCircle *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfCircle *>(geom2))->getCenter();
Base::Vector3d direction=center2-center;
double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar
Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi),
center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0);
Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x);
Base::Vector3d endpoint = PoE+perp;
int currentgeoid= Obj->getHighestCurveIndex();
Gui::Command::openCommand("add tangent constraint");
try {
// Add a construction line
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
Obj->getNameInDocument(),
PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1);
// Point on first object
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
Obj->getNameInDocument(),currentgeoid+1,Sketcher::start,geoId1); // constrain major axis
// Point on second object
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
Obj->getNameInDocument(),currentgeoid+1,Sketcher::start,geoId2); // constrain major axis
// tangent to first object
Gui::Command::doCommand(
Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
Obj->getNameInDocument(),currentgeoid+1,geoId1);
// tangent to second object
Gui::Command::doCommand(
Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
Obj->getNameInDocument(),currentgeoid+1,geoId2);
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
Gui::Command::abortCommand();
Gui::Command::updateActive();
return;
}
Gui::Command::commitCommand();
Gui::Command::updateActive();
}
namespace SketcherGui {
struct SketchSelection{
@@ -1374,6 +1531,9 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
PoE.x,PoE.y,endpoint.x,endpoint.y);
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1);
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Distance',%d,%f)) ",
selection[0].getFeatName(),currentgeoid+1,direction.Length());
// Point on first object (ellipse, arc of ellipse)
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
@@ -1480,6 +1640,97 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
QObject::tr("Cannot add a tangency constraint at an unconnected point!"));
return;
}
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
if( geom1 && geom2 &&
( geom1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ||
geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() )){
if(geom1->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId())
std::swap(GeoId1,GeoId2);
// GeoId1 is the arc of ellipse
geom1 = Obj->getGeometry(GeoId1);
geom2 = Obj->getGeometry(GeoId2);
if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ||
geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) {
const Part::GeomArcOfEllipse *aoe = static_cast<const Part::GeomArcOfEllipse *>(geom1);
Base::Vector3d center=aoe->getCenter();
double majord=aoe->getMajorRadius();
double minord=aoe->getMinorRadius();
double phi=aoe->getAngleXU();
Base::Vector3d center2;
if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfEllipse *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfCircle *>(geom2))->getCenter();
Base::Vector3d direction=center2-center;
double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar
Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi),
center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0);
Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x);
Base::Vector3d endpoint = PoE+perp;
int currentgeoid= Obj->getHighestCurveIndex();
openCommand("add tangent constraint");
try {
// do points coincident
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ",
selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2);
// Add a construction line
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
selection[0].getFeatName(),
PoE.x,PoE.y,endpoint.x,endpoint.y);
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1);
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Distance',%d,%f)) ",
selection[0].getFeatName(),currentgeoid+1,direction.Length());
// Point on first object
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId1); // constrain major axis
// Point on second object
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId2); // constrain major axis
// tangent to first object
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,GeoId1);
// tangent to second object
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,GeoId2);
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
Gui::Command::abortCommand();
Gui::Command::updateActive();
return;
}
commitCommand();
updateActive();
getSelection().clearSelection();
return;
}
}
openCommand("add tangent constraint");
Gui::Command::doCommand(
@@ -1533,82 +1784,11 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
geom2->getTypeId() == Part::GeomCircle::getClassTypeId() ||
geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) {
const Part::GeomEllipse *ellipse = static_cast<const Part::GeomEllipse *>(geom1);
Base::Vector3d center=ellipse->getCenter();
double majord=ellipse->getMajorRadius();
double minord=ellipse->getMinorRadius();
double phi=ellipse->getAngleXU();
Base::Vector3d center2;
if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() )
center2= (static_cast<const Part::GeomEllipse *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfEllipse *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId())
center2= (static_cast<const Part::GeomCircle *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfCircle *>(geom2))->getCenter();
Base::Vector3d direction=center2-center;
double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar
Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi),
center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0);
Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x);
Base::Vector3d endpoint = PoE+perp;
int currentgeoid= Obj->getHighestCurveIndex();
openCommand("add tangent constraint");
try {
//construct the point
/*Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))",
Obj->getNameInDocument(),
PoE.x,PoE.y);*/
// Add a construction line
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
selection[0].getFeatName(),
PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1);
// Point on first object
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId1); // constrain major axis
// Point on second object
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId2); // constrain major axis
// tangent to first object
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,GeoId1);
// tangent to second object
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,GeoId2);
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
Gui::Command::abortCommand();
Gui::Command::updateActive();
return;
}
commitCommand();
updateActive();
Gui::Command::openCommand("add tangent constraint via construction element");
makeTangentToEllipseviaConstructionLine(Obj,geom1,geom2,GeoId1,GeoId2);
getSelection().clearSelection();
return;
}
}
}
if( geom1 && geom2 &&
@@ -1626,70 +1806,8 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
geom2->getTypeId() == Part::GeomCircle::getClassTypeId() ||
geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) {
const Part::GeomArcOfEllipse *aoe = static_cast<const Part::GeomArcOfEllipse *>(geom1);
Base::Vector3d center=aoe->getCenter();
double majord=aoe->getMajorRadius();
double minord=aoe->getMinorRadius();
double phi=aoe->getAngleXU();
Base::Vector3d center2;
if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfEllipse *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId())
center2= (static_cast<const Part::GeomCircle *>(geom2))->getCenter();
else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())
center2= (static_cast<const Part::GeomArcOfCircle *>(geom2))->getCenter();
Base::Vector3d direction=center2-center;
double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar
Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi),
center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0);
Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x);
Base::Vector3d endpoint = PoE+perp;
int currentgeoid= Obj->getHighestCurveIndex();
openCommand("add tangent constraint");
try {
// Add a construction line
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
selection[0].getFeatName(),
PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1);
// Point on first object
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId1); // constrain major axis
// Point on second object
Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId2); // constrain major axis
// tangent to first object
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,GeoId1);
// tangent to second object
Gui::Command::doCommand(
Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ",
selection[0].getFeatName(),currentgeoid+1,GeoId2);
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
Gui::Command::abortCommand();
Gui::Command::updateActive();
return;
}
commitCommand();
updateActive();
Gui::Command::openCommand("add tangent constraint via construction element");
makeTangentToArcOfEllipseviaConstructionLine(Obj,geom1,geom2,GeoId1,GeoId2);
getSelection().clearSelection();
return;
}

View File

@@ -0,0 +1,58 @@
/***************************************************************************
* Copyright (c) 2014 Abdullah.tahiri.yo@gmail.com *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef SKETCHERGUI_CommandConstraints_H
#define SKETCHERGUI_CommandConstraints_H
namespace SketcherGui {
// These functions are declared here to promote code reuse from other modules
/// Makes a tangency constraint using external construction line between
/// geom1 => an ellipse
/// geom2 => any of an ellipse, an arc of ellipse, a circle, or an arc (of circle)
/// NOTE: A command must be opened before calling this function, which this function
/// commits or aborts as appropriate. The reason is for compatibility reasons with
/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp
void makeTangentToEllipseviaConstructionLine(const Sketcher::SketchObject* Obj,
const Part::Geometry *geom1,
const Part::Geometry *geom2,
int geoId1,
int geoId2
);
/// Makes a tangency constraint using external construction line between
/// geom1 => an arc of ellipse
/// geom2 => any of an arc of ellipse, a circle, or an arc (of circle)
/// NOTE: A command must be opened before calling this function, which this function
/// commits or aborts as appropriate. The reason is for compatibility reasons with
/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp
void makeTangentToArcOfEllipseviaConstructionLine(const Sketcher::SketchObject* Obj,
const Part::Geometry *geom1,
const Part::Geometry *geom2,
int geoId1,
int geoId2
);
}
#endif // SKETCHERGUI_DrawSketchHandler_H

View File

@@ -1709,7 +1709,7 @@ public:
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f),
if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - EditCurve[0],
AutoConstraint::CURVE)) {
renderSuggestConstraintsCursor(sugConstr2);
return;
@@ -1928,7 +1928,8 @@ public:
if (method == PERIAPSIS_APOAPSIS_B) {
if (mode == STATUS_SEEK_PERIAPSIS) {
setPositionText(onSketchPos);
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { // TODO: ellipse prio 1
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f),
AutoConstraint::CURVE)) {
renderSuggestConstraintsCursor(sugConstr1);
return;
}
@@ -1945,6 +1946,11 @@ public:
sketchgui->drawEdit(editCurve);
// Suggestions for ellipse and curves are disabled because many tangent constraints
// need an intermediate point or line.
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f),
AutoConstraint::CURVE)) {
renderSuggestConstraintsCursor(sugConstr2);
return;
}
} else if (mode == STATUS_SEEK_B) {
solveEllipse(onSketchPos);
approximateEllipse();
@@ -1955,6 +1961,11 @@ public:
setPositionText(onSketchPos, text);
sketchgui->drawEdit(editCurve);
if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f),
AutoConstraint::CURVE)) {
renderSuggestConstraintsCursor(sugConstr3);
return;
}
}
} else { // method is CENTER_PERIAPSIS_B
if (mode == STATUS_SEEK_CENTROID) {
@@ -1974,6 +1985,11 @@ public:
setPositionText(onSketchPos, text);
sketchgui->drawEdit(editCurve);
if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - centroid,
AutoConstraint::CURVE)) {
renderSuggestConstraintsCursor(sugConstr2);
return;
}
} else if ((mode == STATUS_SEEK_A) || (mode == STATUS_SEEK_B)) {
solveEllipse(onSketchPos);
approximateEllipse();
@@ -1984,6 +2000,11 @@ public:
setPositionText(onSketchPos, text);
sketchgui->drawEdit(editCurve);
if (seekAutoConstraint(sugConstr3, onSketchPos, onSketchPos - centroid,
AutoConstraint::CURVE)) {
renderSuggestConstraintsCursor(sugConstr3);
return;
}
}
}
applyCursor();
@@ -2037,7 +2058,7 @@ public:
return true;
}
protected:
std::vector<AutoConstraint> sugConstr1;
std::vector<AutoConstraint> sugConstr1, sugConstr2, sugConstr3;
private:
SelectMode mode;
/// the method of constructing the ellipse
@@ -2344,7 +2365,6 @@ private:
octave << "plot(centroid(1), centroid(2), \"b.\", \"markersize\", 5);\n";
octave << "plot(f(1), f(2), \"c.\", \"markersize\", 5);\n";
octave << "plot(fPrime(1), fPrime(2), \"m.\", \"markersize\", 5);\n";
octave << "n = [periapsis(1) - f(1), periapsis(2) - f(2)];\n";
octave << "h = quiver(f(1),f(2),n(1),n(2), 0);\n";
octave << "set (h, \"maxheadsize\", 0.1);\n\n";
@@ -2490,67 +2510,10 @@ private:
currentgeoid++;
try {
// create line for major axis
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addGeometry(Part.Line"
"(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
sketchgui->getObject()->getNameInDocument(),
periapsis.fX,periapsis.fY,
apoapsis.fX,apoapsis.fY);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",
sketchgui->getObject()->getNameInDocument(),currentgeoid+1);
// constrain major axis
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint"
"('InternalAlignment:EllipseMajorDiameter',%d,%d)) ",
sketchgui->getObject()->getNameInDocument(),
currentgeoid+1,currentgeoid);
// create line for minor axis
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addGeometry(Part.Line"
"(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
sketchgui->getObject()->getNameInDocument(),
positiveB.fX,positiveB.fY,
negativeB.fX,negativeB.fY);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",
sketchgui->getObject()->getNameInDocument(),currentgeoid+2);
// constrain minor axis
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint"
"('InternalAlignment:EllipseMinorDiameter',%d,%d)) ",
sketchgui->getObject()->getNameInDocument(),
currentgeoid+2,currentgeoid);
// create point for focus
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))",
sketchgui->getObject()->getNameInDocument(),
f.fX,f.fY);
// constrain focus
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint"
"('InternalAlignment:EllipseFocus1',%d,%d,%d)) ",
sketchgui->getObject()->getNameInDocument(),
currentgeoid+3,Sketcher::start,currentgeoid);
// create point for second focus
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))",
sketchgui->getObject()->getNameInDocument(),
fPrime.fX,fPrime.fY);
// constrain second focus
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint"
"('InternalAlignment:EllipseFocus2',%d,%d,%d)) ",
sketchgui->getObject()->getNameInDocument(),
currentgeoid+4,Sketcher::start,currentgeoid);
"App.ActiveDocument.%s.ExposeInternalGeometry(%d)",
sketchgui->getObject()->getNameInDocument(),
currentgeoid);
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
@@ -2562,10 +2525,35 @@ private:
Gui::Command::commitCommand();
Gui::Command::updateActive();
// add auto constraints for the center point
if (sugConstr1.size() > 0) {
createAutoConstraints(sugConstr1, currentgeoid, Sketcher::mid);
sugConstr1.clear();
if (method == CENTER_PERIAPSIS_B) {
// add auto constraints for the center point
if (sugConstr1.size() > 0) {
createAutoConstraints(sugConstr1, currentgeoid, Sketcher::mid);
sugConstr1.clear();
}
if (sugConstr2.size() > 0) {
createAutoConstraints(sugConstr2, currentgeoid, Sketcher::none);
sugConstr2.clear();
}
if (sugConstr3.size() > 0) {
createAutoConstraints(sugConstr3, currentgeoid, Sketcher::none);
sugConstr3.clear();
}
}
if (method == PERIAPSIS_APOAPSIS_B) {
if (sugConstr1.size() > 0) {
createAutoConstraints(sugConstr1, currentgeoid, Sketcher::none);
sugConstr1.clear();
}
if (sugConstr2.size() > 0) {
createAutoConstraints(sugConstr2, currentgeoid, Sketcher::none);
sugConstr2.clear();
}
if (sugConstr3.size() > 0) {
createAutoConstraints(sugConstr3, currentgeoid, Sketcher::none);
sugConstr3.clear();
}
}
// delete the temp construction curve from the sketch
@@ -2720,11 +2708,11 @@ public:
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f),
if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos - centerPoint,
AutoConstraint::CURVE)) {
renderSuggestConstraintsCursor(sugConstr2);
return;
}
}
}
else if (Mode==STATUS_SEEK_Third) {
// angle between the major axis of the ellipse and the X axis
@@ -2751,8 +2739,7 @@ public:
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f),
AutoConstraint::CURVE)) {
if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr3);
return;
}
@@ -2791,8 +2778,7 @@ public:
setPositionText(onSketchPos, text);
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr4, onSketchPos, Base::Vector2D(0.f,0.f),
AutoConstraint::CURVE)) {
if (seekAutoConstraint(sugConstr4, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr4);
return;
}
@@ -2849,11 +2835,14 @@ public:
double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ;
arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;
bool isOriginalArcCCW=true;
if (arcAngle > 0)
endAngle = startAngle + arcAngle;
else {
endAngle = startAngle;
startAngle += arcAngle;
isOriginalArcCCW=false;
}
Base::Vector2D majAxisDir,minAxisDir,minAxisPoint,majAxisPoint;
@@ -2883,19 +2872,7 @@ public:
phi-=M_PI/2;
double t=a; a=b; b=t;//swap a,b
}
Base::Vector3d center = Base::Vector3d(centerPoint.fX,centerPoint.fY,0);
Base::Vector3d majorpositiveend = center + a * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d majornegativeend = center - a * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d minorpositiveend = center + b * Base::Vector3d(-sin(phi),cos(phi),0);
Base::Vector3d minornegativeend = center - b * Base::Vector3d(-sin(phi),cos(phi),0);
double cf = sqrt( abs(a*a - b*b) );//using abs, avoided using different formula for a>b/a<b cases
Base::Vector3d focus1P = center + cf * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d focus2P = center - cf * Base::Vector3d(cos(phi),sin(phi),0);
int currentgeoid = getHighestCurveIndex();
Gui::Command::openCommand("Add sketch arc of ellipse");
@@ -2913,39 +2890,10 @@ public:
currentgeoid++;
try {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
sketchgui->getObject()->getNameInDocument(),
majorpositiveend.x,majorpositiveend.y,majornegativeend.x,majornegativeend.y); // create line for major axis
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",
sketchgui->getObject()->getNameInDocument(),currentgeoid+1);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMajorDiameter',%d,%d)) ",
sketchgui->getObject()->getNameInDocument(),currentgeoid+1,currentgeoid); // constrain major axis
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))",
sketchgui->getObject()->getNameInDocument(),
minorpositiveend.x,minorpositiveend.y,minornegativeend.x,minornegativeend.y); // create line for minor axis
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",
sketchgui->getObject()->getNameInDocument(),currentgeoid+2);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMinorDiameter',%d,%d)) ",
sketchgui->getObject()->getNameInDocument(),currentgeoid+2,currentgeoid); // constrain minor axis
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))",
sketchgui->getObject()->getNameInDocument(),
focus1P.x,focus1P.y);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus1',%d,%d,%d)) ",
sketchgui->getObject()->getNameInDocument(),currentgeoid+3,Sketcher::start,currentgeoid);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))",
sketchgui->getObject()->getNameInDocument(),
focus2P.x,focus2P.y);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus2',%d,%d,%d)) ",
sketchgui->getObject()->getNameInDocument(),currentgeoid+4,Sketcher::start,currentgeoid);
Gui::Command::doCommand(Gui::Command::Doc,
"App.ActiveDocument.%s.ExposeInternalGeometry(%d)",
sketchgui->getObject()->getNameInDocument(),
currentgeoid);
}
catch (const Base::Exception& e) {
Base::Console().Error("%s\n", e.what());
@@ -2959,15 +2907,27 @@ public:
// add auto constraints for the center point
if (sugConstr1.size() > 0) {
createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::mid);
createAutoConstraints(sugConstr1, currentgeoid, Sketcher::mid);
sugConstr1.clear();
}
// add suggested constraints for circumference
// add suggested constraints for arc
if (sugConstr2.size() > 0) {
//createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::none);
createAutoConstraints(sugConstr2, currentgeoid, Sketcher::none);
sugConstr2.clear();
}
// add suggested constraints for start of arc
if (sugConstr3.size() > 0) {
createAutoConstraints(sugConstr3, currentgeoid, isOriginalArcCCW?Sketcher::start:Sketcher::end);
sugConstr3.clear();
}
// add suggested constraints for start of arc
if (sugConstr4.size() > 0) {
createAutoConstraints(sugConstr4, currentgeoid, isOriginalArcCCW?Sketcher::end:Sketcher::start);
sugConstr4.clear();
}
EditCurve.clear();
sketchgui->drawEdit(EditCurve);

View File

@@ -35,6 +35,7 @@
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Interpreter.h>
#include <Base/Tools.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Command.h>
@@ -49,6 +50,7 @@
#include "DrawSketchHandler.h"
#include "ViewProviderSketch.h"
#include "CommandConstraints.h"
using namespace SketcherGui;
@@ -138,6 +140,8 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
if (!sketchgui->Autoconstraints.getValue())
return 0; // If Autoconstraints property is not set quit
Base::Vector3d hitShapeDir = Base::Vector3d(0,0,0); // direction of hit shape (if it is a line, the direction of the line)
// Get Preselection
int preSelPnt = sketchgui->getPreselectPoint();
int preSelCrv = sketchgui->getPreselectCurve();
@@ -146,16 +150,29 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
Sketcher::PointPos PosId = Sketcher::none;
if (preSelPnt != -1)
sketchgui->getSketchObject()->getGeoVertexIndex(preSelPnt, GeoId, PosId);
else if (preSelCrv != -1)
else if (preSelCrv != -1){
GeoId = preSelCrv;
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(GeoId);
if(geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()){
const Part::GeomLineSegment *line = static_cast<const Part::GeomLineSegment *>(geom);
hitShapeDir= line->getEndPoint()-line->getStartPoint();
}
}
else if (preSelCrs == 0) { // root point
GeoId = -1;
PosId = Sketcher::start;
}
else if (preSelCrs == 1) // x axis
else if (preSelCrs == 1){ // x axis
GeoId = -1;
else if (preSelCrs == 2) // y axis
hitShapeDir = Base::Vector3d(1,0,0);
}
else if (preSelCrs == 2){ // y axis
GeoId = -2;
hitShapeDir = Base::Vector3d(0,1,0);
}
if (GeoId != Constraint::GeoUndef) {
// Currently only considers objects in current Sketcher
@@ -171,12 +188,25 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
constr.Type = Sketcher::PointOnObject;
else if (type == AutoConstraint::CURVE && PosId == Sketcher::none)
constr.Type = Sketcher::Tangent;
if(constr.Type == Sketcher::Tangent && Dir.Length() > 1e-8 && hitShapeDir.Length() > 1e-8) { // We are hitting a line and have hitting vector information
Base::Vector3d dir3d = Base::Vector3d(Dir.fX,Dir.fY,0);
double cosangle=dir3d.Normalize()*hitShapeDir.Normalize();
// the angle between the line and the hitting direction are over around 6 degrees (it is substantially parallel)
// or if it is an sketch axis (that can not move to accomodate to the shape), then only if it is around 6 degrees with the normal (around 84 degrees)
if(abs(cosangle) < 0.995f || ((GeoId==-1 || GeoId==-2) && abs(cosangle) < 0.1))
suggestedConstraints.push_back(constr);
return suggestedConstraints.size();
}
if (constr.Type != Sketcher::None)
suggestedConstraints.push_back(constr);
}
if (Dir.Length() < 1e-8)
if (Dir.Length() < 1e-8 || type == AutoConstraint::CURVE)
// Direction not set so return;
return suggestedConstraints.size();
@@ -263,8 +293,8 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
Base::Vector3d focus1PMirrored = focus1P + 2*distancetoline*norm; // mirror of focus1 with respect to the line
double error = abs((focus1PMirrored-focus2P).Length() - 2*a);
if ( error< tangDeviation ) {
if ( error< tangDeviation) {
tangId = i;
tangDeviation = error;
}
@@ -297,7 +327,52 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
tangDeviation = projDist;
}
}
}
} else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) {
const Part::GeomArcOfEllipse *aoe = dynamic_cast<const Part::GeomArcOfEllipse *>((*it));
Base::Vector3d center = aoe->getCenter();
double a = aoe->getMajorRadius();
double b = aoe->getMinorRadius();
double phi = aoe->getAngleXU();
double cf = sqrt(a*a - b*b);
Base::Vector3d focus1P = center + cf * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d focus2P = center - cf * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d norm = Base::Vector3d(Dir.fY,-Dir.fX).Normalize();
double distancetoline = norm*(tmpPos - focus1P); // distance focus1 to line
Base::Vector3d focus1PMirrored = focus1P + 2*distancetoline*norm; // mirror of focus1 with respect to the line
double error = abs((focus1PMirrored-focus2P).Length() - 2*a);
if ( error< tangDeviation ) {
tangId = i;
tangDeviation = error;
}
if (error < tangDeviation) {
double startAngle, endAngle;
aoe->getRange(startAngle, endAngle);
double angle = Base::fmod(
atan2(-aoe->getMajorRadius()*((tmpPos.x-center.x)*sin(aoe->getAngleXU())-(tmpPos.y-center.y)*cos(aoe->getAngleXU())),
aoe->getMinorRadius()*((tmpPos.x-center.x)*cos(aoe->getAngleXU())+(tmpPos.y-center.y)*sin(aoe->getAngleXU()))
)- startAngle, 2.f*M_PI);
while(angle < startAngle)
angle += 2*D_PI; // Bring it to range of arc
// if the point is on correct side of arc
if (angle <= endAngle) { // Now need to check only one side
tangId = i;
tangDeviation = error;
}
}
}
}
if (tangId != Constraint::GeoUndef) {
@@ -364,6 +439,58 @@ void DrawSketchHandler::createAutoConstraints(const std::vector<AutoConstraint>
);
} break;
case Sketcher::Tangent: {
Sketcher::SketchObject* Obj = dynamic_cast<Sketcher::SketchObject*>(sketchgui->getObject());
const Part::Geometry *geom1 = Obj->getGeometry(geoId1);
const Part::Geometry *geom2 = Obj->getGeometry(it->GeoId);
int geoId2 = it->GeoId;
// ellipse tangency support using construction elements (lines)
if( geom1 && geom2 &&
( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() ||
geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() )){
if(geom1->getTypeId() != Part::GeomEllipse::getClassTypeId())
std::swap(geoId1,geoId2);
// geoId1 is the ellipse
geom1 = Obj->getGeometry(geoId1);
geom2 = Obj->getGeometry(geoId2);
if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() ||
geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ||
geom2->getTypeId() == Part::GeomCircle::getClassTypeId() ||
geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) {
// in all these cases an intermediate element is needed
makeTangentToEllipseviaConstructionLine(Obj,geom1,geom2,geoId1,geoId2);
return;
}
}
// arc of ellipse tangency support using external elements
if( geom1 && geom2 &&
( geom1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ||
geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() )){
if(geom1->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId())
std::swap(geoId1,geoId2);
// geoId1 is the arc of ellipse
geom1 = Obj->getGeometry(geoId1);
geom2 = Obj->getGeometry(geoId2);
if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ||
geom2->getTypeId() == Part::GeomCircle::getClassTypeId() ||
geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) {
// in all these cases an intermediate element is needed
// TODO: INSERT COMMON CODE HERE
// in all these cases an intermediate element is needed
makeTangentToArcOfEllipseviaConstructionLine(Obj,geom1,geom2,geoId1,geoId2);
return;
}
}
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%i, %i)) "
,sketchgui->getObject()->getNameInDocument()
,geoId1, it->GeoId