2016 lines
72 KiB
C++
2016 lines
72 KiB
C++
/***************************************************************************
|
|
* Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2010 *
|
|
* *
|
|
* 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 *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#include "PreCompiled.h"
|
|
#ifndef _PreComp_
|
|
# include <BRep_Builder.hxx>
|
|
# include <Precision.hxx>
|
|
# include <ShapeFix_Wire.hxx>
|
|
# include <TopoDS_Compound.hxx>
|
|
#endif
|
|
|
|
#include <Base/Writer.h>
|
|
#include <Base/Reader.h>
|
|
#include <Base/Exception.h>
|
|
#include <Base/TimeInfo.h>
|
|
#include <Base/Console.h>
|
|
|
|
#include <Base/VectorPy.h>
|
|
|
|
#include <Mod/Part/App/Geometry.h>
|
|
#include <Mod/Part/App/GeometryCurvePy.h>
|
|
#include <Mod/Part/App/ArcOfCirclePy.h>
|
|
#include <Mod/Part/App/CirclePy.h>
|
|
#include <Mod/Part/App/EllipsePy.h>
|
|
#include <Mod/Part/App/LinePy.h>
|
|
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Edge.hxx>
|
|
#include <BRepBuilderAPI_MakeWire.hxx>
|
|
|
|
#include "Sketch.h"
|
|
#include "Constraint.h"
|
|
#include <cmath>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
using namespace Sketcher;
|
|
using namespace Base;
|
|
using namespace Part;
|
|
|
|
TYPESYSTEM_SOURCE(Sketcher::Sketch, Base::Persistence)
|
|
|
|
Sketch::Sketch()
|
|
: GCSsys(), ConstraintsCounter(0), isInitMove(false)
|
|
{
|
|
}
|
|
|
|
Sketch::~Sketch()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void Sketch::clear(void)
|
|
{
|
|
// clear all internal data sets
|
|
Points.clear();
|
|
Lines.clear();
|
|
Arcs.clear();
|
|
Circles.clear();
|
|
|
|
// deleting the doubles allocated with new
|
|
for (std::vector<double*>::iterator it = Parameters.begin(); it != Parameters.end(); ++it)
|
|
if (*it) delete *it;
|
|
Parameters.clear();
|
|
for (std::vector<double*>::iterator it = FixParameters.begin(); it != FixParameters.end(); ++it)
|
|
if (*it) delete *it;
|
|
FixParameters.clear();
|
|
|
|
// deleting the geometry copied into this sketch
|
|
for (std::vector<GeoDef>::iterator it = Geoms.begin(); it != Geoms.end(); ++it)
|
|
if (it->geo) delete it->geo;
|
|
Geoms.clear();
|
|
|
|
GCSsys.clear();
|
|
isInitMove = false;
|
|
ConstraintsCounter = 0;
|
|
Conflicting.clear();
|
|
}
|
|
|
|
int Sketch::setUpSketch(const std::vector<Part::Geometry *> &GeoList,
|
|
const std::vector<Constraint *> &ConstraintList,
|
|
int extGeoCount)
|
|
{
|
|
clear();
|
|
|
|
std::vector<Part::Geometry *> intGeoList, extGeoList;
|
|
for (int i=0; i < int(GeoList.size())-extGeoCount; i++)
|
|
intGeoList.push_back(GeoList[i]);
|
|
for (int i=int(GeoList.size())-extGeoCount; i < int(GeoList.size()); i++)
|
|
extGeoList.push_back(GeoList[i]);
|
|
|
|
addGeometry(intGeoList);
|
|
int extStart=Geoms.size();
|
|
addGeometry(extGeoList, true);
|
|
int extEnd=Geoms.size()-1;
|
|
for (int i=extStart; i <= extEnd; i++)
|
|
Geoms[i].external = true;
|
|
|
|
// The Geoms list might be empty after an undo/redo
|
|
if (!Geoms.empty())
|
|
addConstraints(ConstraintList);
|
|
|
|
GCSsys.clearByTag(-1);
|
|
GCSsys.declareUnknowns(Parameters);
|
|
GCSsys.initSolution();
|
|
GCSsys.getConflicting(Conflicting);
|
|
GCSsys.getRedundant(Redundant);
|
|
return GCSsys.dofsNumber();
|
|
}
|
|
|
|
const char* nameByType(Sketch::GeoType type)
|
|
{
|
|
switch (type) {
|
|
case Sketch::Point:
|
|
return "point";
|
|
case Sketch::Line:
|
|
return "line";
|
|
case Sketch::Arc:
|
|
return "arc";
|
|
case Sketch::Circle:
|
|
return "circle";
|
|
case Sketch::Ellipse:
|
|
return "ellipse";
|
|
case Sketch::None:
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
// Geometry adding ==========================================================
|
|
|
|
int Sketch::addGeometry(const Part::Geometry *geo, bool fixed)
|
|
{
|
|
if (geo->getTypeId() == GeomPoint::getClassTypeId()) { // add a point
|
|
const GeomPoint *point = dynamic_cast<const GeomPoint*>(geo);
|
|
// create the definition struct for that geom
|
|
return addPoint(*point, fixed);
|
|
} else if (geo->getTypeId() == GeomLineSegment::getClassTypeId()) { // add a line
|
|
const GeomLineSegment *lineSeg = dynamic_cast<const GeomLineSegment*>(geo);
|
|
// create the definition struct for that geom
|
|
return addLineSegment(*lineSeg, fixed);
|
|
} else if (geo->getTypeId() == GeomCircle::getClassTypeId()) { // add a circle
|
|
const GeomCircle *circle = dynamic_cast<const GeomCircle*>(geo);
|
|
// create the definition struct for that geom
|
|
return addCircle(*circle, fixed);
|
|
} else if (geo->getTypeId() == GeomArcOfCircle::getClassTypeId()) { // add an arc
|
|
const GeomArcOfCircle *aoc = dynamic_cast<const GeomArcOfCircle*>(geo);
|
|
// create the definition struct for that geom
|
|
return addArc(*aoc, fixed);
|
|
} else {
|
|
Base::Exception("Sketch::addGeometry(): Unknown or unsupported type added to a sketch");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int Sketch::addGeometry(const std::vector<Part::Geometry *> &geo, bool fixed)
|
|
{
|
|
int ret = -1;
|
|
for (std::vector<Part::Geometry *>::const_iterator it=geo.begin(); it != geo.end(); ++it)
|
|
ret = addGeometry(*it, fixed);
|
|
return ret;
|
|
}
|
|
|
|
int Sketch::addPoint(const Part::GeomPoint &point, bool fixed)
|
|
{
|
|
std::vector<double *> ¶ms = fixed ? FixParameters : Parameters;
|
|
|
|
// create our own copy
|
|
GeomPoint *p = static_cast<GeomPoint*>(point.clone());
|
|
// points in a sketch are always construction elements
|
|
p->Construction = true;
|
|
// create the definition struct for that geom
|
|
GeoDef def;
|
|
def.geo = p;
|
|
def.type = Point;
|
|
|
|
// set the parameter for the solver
|
|
params.push_back(new double(p->getPoint().x));
|
|
params.push_back(new double(p->getPoint().y));
|
|
|
|
// set the points for later constraints
|
|
GCS::Point p1;
|
|
p1.x = params[params.size()-2];
|
|
p1.y = params[params.size()-1];
|
|
def.startPointId = Points.size();
|
|
def.endPointId = Points.size();
|
|
def.midPointId = Points.size();
|
|
Points.push_back(p1);
|
|
|
|
// store complete set
|
|
Geoms.push_back(def);
|
|
|
|
// return the position of the newly added geometry
|
|
return Geoms.size()-1;
|
|
}
|
|
|
|
int Sketch::addLine(const Part::GeomLineSegment &line, bool fixed)
|
|
{
|
|
|
|
// return the position of the newly added geometry
|
|
return Geoms.size()-1;
|
|
}
|
|
|
|
int Sketch::addLineSegment(const Part::GeomLineSegment &lineSegment, bool fixed)
|
|
{
|
|
std::vector<double *> ¶ms = fixed ? FixParameters : Parameters;
|
|
|
|
// create our own copy
|
|
GeomLineSegment *lineSeg = static_cast<GeomLineSegment*>(lineSegment.clone());
|
|
// create the definition struct for that geom
|
|
GeoDef def;
|
|
def.geo = lineSeg;
|
|
def.type = Line;
|
|
|
|
// get the points from the line
|
|
Base::Vector3d start = lineSeg->getStartPoint();
|
|
Base::Vector3d end = lineSeg->getEndPoint();
|
|
|
|
// the points for later constraints
|
|
GCS::Point p1, p2;
|
|
|
|
params.push_back(new double(start.x));
|
|
params.push_back(new double(start.y));
|
|
p1.x = params[params.size()-2];
|
|
p1.y = params[params.size()-1];
|
|
|
|
params.push_back(new double(end.x));
|
|
params.push_back(new double(end.y));
|
|
p2.x = params[params.size()-2];
|
|
p2.y = params[params.size()-1];
|
|
|
|
// add the points
|
|
def.startPointId = Points.size();
|
|
def.endPointId = Points.size()+1;
|
|
Points.push_back(p1);
|
|
Points.push_back(p2);
|
|
|
|
// set the line for later constraints
|
|
GCS::Line l;
|
|
l.p1 = p1;
|
|
l.p2 = p2;
|
|
def.index = Lines.size();
|
|
Lines.push_back(l);
|
|
|
|
// store complete set
|
|
Geoms.push_back(def);
|
|
|
|
// return the position of the newly added geometry
|
|
return Geoms.size()-1;
|
|
}
|
|
|
|
int Sketch::addArc(const Part::GeomArcOfCircle &circleSegment, bool fixed)
|
|
{
|
|
std::vector<double *> ¶ms = fixed ? FixParameters : Parameters;
|
|
|
|
// create our own copy
|
|
GeomArcOfCircle *aoc = static_cast<GeomArcOfCircle*>(circleSegment.clone());
|
|
// create the definition struct for that geom
|
|
GeoDef def;
|
|
def.geo = aoc;
|
|
def.type = Arc;
|
|
|
|
Base::Vector3d center = aoc->getCenter();
|
|
Base::Vector3d startPnt = aoc->getStartPoint();
|
|
Base::Vector3d endPnt = aoc->getEndPoint();
|
|
double radius = aoc->getRadius();
|
|
double startAngle, endAngle;
|
|
aoc->getRange(startAngle, endAngle);
|
|
|
|
GCS::Point p1, p2, p3;
|
|
|
|
params.push_back(new double(startPnt.x));
|
|
params.push_back(new double(startPnt.y));
|
|
p1.x = params[params.size()-2];
|
|
p1.y = params[params.size()-1];
|
|
|
|
params.push_back(new double(endPnt.x));
|
|
params.push_back(new double(endPnt.y));
|
|
p2.x = params[params.size()-2];
|
|
p2.y = params[params.size()-1];
|
|
|
|
params.push_back(new double(center.x));
|
|
params.push_back(new double(center.y));
|
|
p3.x = params[params.size()-2];
|
|
p3.y = params[params.size()-1];
|
|
|
|
def.startPointId = Points.size();
|
|
Points.push_back(p1);
|
|
def.endPointId = Points.size();
|
|
Points.push_back(p2);
|
|
def.midPointId = Points.size();
|
|
Points.push_back(p3);
|
|
|
|
params.push_back(new double(radius));
|
|
double *r = params[params.size()-1];
|
|
params.push_back(new double(startAngle));
|
|
double *a1 = params[params.size()-1];
|
|
params.push_back(new double(endAngle));
|
|
double *a2 = params[params.size()-1];
|
|
|
|
// set the arc for later constraints
|
|
GCS::Arc a;
|
|
a.start = p1;
|
|
a.end = p2;
|
|
a.center = p3;
|
|
a.rad = r;
|
|
a.startAngle = a1;
|
|
a.endAngle = a2;
|
|
def.index = Arcs.size();
|
|
Arcs.push_back(a);
|
|
|
|
// store complete set
|
|
Geoms.push_back(def);
|
|
|
|
// arcs require an ArcRules constraint for the end points
|
|
if (!fixed)
|
|
GCSsys.addConstraintArcRules(a);
|
|
|
|
// return the position of the newly added geometry
|
|
return Geoms.size()-1;
|
|
}
|
|
|
|
int Sketch::addCircle(const Part::GeomCircle &cir, bool fixed)
|
|
{
|
|
std::vector<double *> ¶ms = fixed ? FixParameters : Parameters;
|
|
|
|
// create our own copy
|
|
GeomCircle *circ = static_cast<GeomCircle*>(cir.clone());
|
|
// create the definition struct for that geom
|
|
GeoDef def;
|
|
def.geo = circ;
|
|
def.type = Circle;
|
|
|
|
Base::Vector3d center = circ->getCenter();
|
|
double radius = circ->getRadius();
|
|
|
|
GCS::Point p1;
|
|
|
|
params.push_back(new double(center.x));
|
|
params.push_back(new double(center.y));
|
|
p1.x = params[params.size()-2];
|
|
p1.y = params[params.size()-1];
|
|
|
|
params.push_back(new double(radius));
|
|
|
|
def.midPointId = Points.size();
|
|
Points.push_back(p1);
|
|
|
|
// add the radius parameter
|
|
double *r = params[params.size()-1];
|
|
|
|
// set the circle for later constraints
|
|
GCS::Circle c;
|
|
c.center = p1;
|
|
c.rad = r;
|
|
def.index = Circles.size();
|
|
Circles.push_back(c);
|
|
|
|
// store complete set
|
|
Geoms.push_back(def);
|
|
|
|
// return the position of the newly added geometry
|
|
return Geoms.size()-1;
|
|
}
|
|
|
|
int Sketch::addEllipse(const Part::GeomEllipse &ellipse, bool fixed)
|
|
{
|
|
// return the position of the newly added geometry
|
|
return Geoms.size()-1;
|
|
}
|
|
|
|
std::vector<Part::Geometry *> Sketch::extractGeometry(bool withConstrucionElements,
|
|
bool withExternalElements) const
|
|
{
|
|
std::vector<Part::Geometry *> temp;
|
|
temp.reserve(Geoms.size());
|
|
for (std::vector<GeoDef>::const_iterator it=Geoms.begin(); it != Geoms.end(); ++it)
|
|
if ((!it->external || withExternalElements) && (!it->geo->Construction || withConstrucionElements))
|
|
temp.push_back(it->geo->clone());
|
|
|
|
return temp;
|
|
}
|
|
|
|
Py::Tuple Sketch::getPyGeometry(void) const
|
|
{
|
|
Py::Tuple tuple(Geoms.size());
|
|
int i=0;
|
|
for (std::vector<GeoDef>::const_iterator it=Geoms.begin(); it != Geoms.end(); ++it, i++) {
|
|
if (it->type == Point) {
|
|
Base::Vector3d temp(*(Points[it->startPointId].x),*(Points[it->startPointId].y),0);
|
|
tuple[i] = Py::asObject(new VectorPy(temp));
|
|
} else if (it->type == Line) {
|
|
GeomLineSegment *lineSeg = dynamic_cast<GeomLineSegment*>(it->geo->clone());
|
|
tuple[i] = Py::asObject(new LinePy(lineSeg));
|
|
} else if (it->type == Arc) {
|
|
GeomArcOfCircle *aoc = dynamic_cast<GeomArcOfCircle*>(it->geo->clone());
|
|
tuple[i] = Py::asObject(new ArcOfCirclePy(aoc));
|
|
} else if (it->type == Circle) {
|
|
GeomCircle *circle = dynamic_cast<GeomCircle*>(it->geo->clone());
|
|
tuple[i] = Py::asObject(new CirclePy(circle));
|
|
} else if (it->type == Ellipse) {
|
|
GeomEllipse *ellipse = dynamic_cast<GeomEllipse*>(it->geo->clone());
|
|
tuple[i] = Py::asObject(new EllipsePy(ellipse));
|
|
} else {
|
|
// not implemented type in the sketch!
|
|
}
|
|
}
|
|
return tuple;
|
|
}
|
|
|
|
int Sketch::checkGeoId(int geoId)
|
|
{
|
|
if (geoId < 0)
|
|
geoId += Geoms.size();
|
|
assert(geoId >= 0 && geoId < int(Geoms.size()));
|
|
return geoId;
|
|
}
|
|
|
|
// constraint adding ==========================================================
|
|
|
|
int Sketch::addConstraint(const Constraint *constraint)
|
|
{
|
|
// constraints on nothing makes no sense
|
|
assert(int(Geoms.size()) > 0);
|
|
int rtn = -1;
|
|
switch (constraint->Type) {
|
|
case DistanceX:
|
|
if (constraint->FirstPos == none) // horizontal length of a line
|
|
rtn = addDistanceXConstraint(constraint->First,constraint->Value);
|
|
else if (constraint->Second == Constraint::GeoUndef) // point on fixed x-coordinate
|
|
rtn = addCoordinateXConstraint(constraint->First,constraint->FirstPos,constraint->Value);
|
|
else if (constraint->SecondPos != none) // point to point horizontal distance
|
|
rtn = addDistanceXConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos,constraint->Value);
|
|
break;
|
|
case DistanceY:
|
|
if (constraint->FirstPos == none) // vertical length of a line
|
|
rtn = addDistanceYConstraint(constraint->First,constraint->Value);
|
|
else if (constraint->Second == Constraint::GeoUndef) // point on fixed y-coordinate
|
|
rtn = addCoordinateYConstraint(constraint->First,constraint->FirstPos,constraint->Value);
|
|
else if (constraint->SecondPos != none) // point to point vertical distance
|
|
rtn = addDistanceYConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos,constraint->Value);
|
|
break;
|
|
case Horizontal:
|
|
if (constraint->Second == Constraint::GeoUndef) // horizontal line
|
|
rtn = addHorizontalConstraint(constraint->First);
|
|
else // two points on the same horizontal line
|
|
rtn = addHorizontalConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos);
|
|
break;
|
|
case Vertical:
|
|
if (constraint->Second == Constraint::GeoUndef) // vertical line
|
|
rtn = addVerticalConstraint(constraint->First);
|
|
else // two points on the same vertical line
|
|
rtn = addVerticalConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos);
|
|
break;
|
|
case Coincident:
|
|
rtn = addPointCoincidentConstraint(constraint->First,constraint->FirstPos,constraint->Second,constraint->SecondPos);
|
|
break;
|
|
case PointOnObject:
|
|
rtn = addPointOnObjectConstraint(constraint->First,constraint->FirstPos, constraint->Second);
|
|
break;
|
|
case Parallel:
|
|
rtn = addParallelConstraint(constraint->First,constraint->Second);
|
|
break;
|
|
case Perpendicular:
|
|
if (constraint->SecondPos != none) // perpendicularity at common point
|
|
rtn = addPerpendicularConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos);
|
|
else if (constraint->Second != Constraint::GeoUndef) {
|
|
if (constraint->FirstPos != none) // "First" is a connecting point
|
|
rtn = addPerpendicularConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second);
|
|
else // simple perpendicularity
|
|
rtn = addPerpendicularConstraint(constraint->First,constraint->Second);
|
|
}
|
|
break;
|
|
case Tangent:
|
|
if (constraint->SecondPos != none) // tangency at common point
|
|
rtn = addTangentConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos);
|
|
else if (constraint->Second != Constraint::GeoUndef) {
|
|
if (constraint->FirstPos != none) // "First" is a tangency point
|
|
rtn = addTangentConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second);
|
|
else // simple tangency
|
|
rtn = addTangentConstraint(constraint->First,constraint->Second);
|
|
}
|
|
break;
|
|
case Distance:
|
|
if (constraint->SecondPos != none) // point to point distance
|
|
rtn = addDistanceConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos,
|
|
constraint->Value);
|
|
else if (constraint->Second != Constraint::GeoUndef) {
|
|
if (constraint->FirstPos != none) // point to line distance
|
|
rtn = addDistanceConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->Value);
|
|
else // line to line distance (not implemented yet)
|
|
rtn = addDistanceConstraint(constraint->First,constraint->Second,constraint->Value);
|
|
}
|
|
else // line length
|
|
rtn = addDistanceConstraint(constraint->First,constraint->Value);
|
|
break;
|
|
case Angle:
|
|
if (constraint->SecondPos != none) // angle between two lines (with explicit start points)
|
|
rtn = addAngleConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos,constraint->Value);
|
|
else if (constraint->Second != Constraint::GeoUndef) // angle between two lines
|
|
rtn = addAngleConstraint(constraint->First,constraint->Second,constraint->Value);
|
|
else if (constraint->First != Constraint::GeoUndef) // orientation angle of a line
|
|
rtn = addAngleConstraint(constraint->First,constraint->Value);
|
|
break;
|
|
case Radius:
|
|
rtn = addRadiusConstraint(constraint->First, constraint->Value);
|
|
break;
|
|
case Equal:
|
|
rtn = addEqualConstraint(constraint->First,constraint->Second);
|
|
break;
|
|
case Symmetric:
|
|
if (constraint->ThirdPos != none)
|
|
rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos,
|
|
constraint->Third,constraint->ThirdPos);
|
|
else
|
|
rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos,
|
|
constraint->Second,constraint->SecondPos,constraint->Third);
|
|
break;
|
|
case None:
|
|
break;
|
|
}
|
|
return rtn;
|
|
}
|
|
|
|
int Sketch::addConstraints(const std::vector<Constraint *> &ConstraintList)
|
|
{
|
|
// constraints on nothing makes no sense
|
|
assert(!Geoms.empty() || ConstraintList.empty());
|
|
|
|
int rtn = -1;
|
|
for (std::vector<Constraint *>::const_iterator it = ConstraintList.begin();it!=ConstraintList.end();++it)
|
|
rtn = addConstraint (*it);
|
|
|
|
return rtn;
|
|
}
|
|
|
|
int Sketch::addCoordinateXConstraint(int geoId, PointPos pos, double value)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
int pointId = getPointId(geoId, pos);
|
|
|
|
if (pointId >= 0 && pointId < int(Points.size())) {
|
|
double *val = new double(value);
|
|
FixParameters.push_back(val);
|
|
GCS::Point &p = Points[pointId];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintCoordinateX(p, val, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int Sketch::addCoordinateYConstraint(int geoId, PointPos pos, double value)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
int pointId = getPointId(geoId, pos);
|
|
|
|
if (pointId >= 0 && pointId < int(Points.size())) {
|
|
double *val = new double(value);
|
|
FixParameters.push_back(val);
|
|
GCS::Point &p = Points[pointId];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintCoordinateY(p, val, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int Sketch::addDistanceXConstraint(int geoId, double value)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
if (Geoms[geoId].type != Line)
|
|
return -1;
|
|
|
|
GCS::Line &l = Lines[Geoms[geoId].index];
|
|
|
|
FixParameters.push_back(new double(value));
|
|
double *diff = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintDifference(l.p1.x, l.p2.x, diff, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
int Sketch::addDistanceYConstraint(int geoId, double value)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
if (Geoms[geoId].type != Line)
|
|
return -1;
|
|
|
|
GCS::Line &l = Lines[Geoms[geoId].index];
|
|
|
|
FixParameters.push_back(new double(value));
|
|
double *diff = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintDifference(l.p1.y, l.p2.y, diff, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
int Sketch::addDistanceXConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
|
|
pointId2 >= 0 && pointId2 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
|
|
FixParameters.push_back(new double(value));
|
|
double *difference = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintDifference(p1.x, p2.x, difference, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int Sketch::addDistanceYConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
|
|
pointId2 >= 0 && pointId2 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
|
|
FixParameters.push_back(new double(value));
|
|
double *difference = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintDifference(p1.y, p2.y, difference, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// horizontal line constraint
|
|
int Sketch::addHorizontalConstraint(int geoId)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
if (Geoms[geoId].type != Line)
|
|
return -1;
|
|
|
|
GCS::Line &l = Lines[Geoms[geoId].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintHorizontal(l, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
// two points on a horizontal line constraint
|
|
int Sketch::addHorizontalConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
|
|
pointId2 >= 0 && pointId2 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintHorizontal(p1, p2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// vertical line constraint
|
|
int Sketch::addVerticalConstraint(int geoId)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
if (Geoms[geoId].type != Line)
|
|
return -1;
|
|
|
|
GCS::Line &l = Lines[Geoms[geoId].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintVertical(l, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
// two points on a vertical line constraint
|
|
int Sketch::addVerticalConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
|
|
pointId2 >= 0 && pointId2 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintVertical(p1, p2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int Sketch::addPointCoincidentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
|
|
pointId2 >= 0 && pointId2 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintP2PCoincident(p1, p2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int Sketch::addParallelConstraint(int geoId1, int geoId2)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
if (Geoms[geoId1].type != Line ||
|
|
Geoms[geoId2].type != Line)
|
|
return -1;
|
|
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintParallel(l1, l2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
// simple perpendicularity constraint
|
|
int Sketch::addPerpendicularConstraint(int geoId1, int geoId2)
|
|
{
|
|
// accepts the following combinations:
|
|
// 1) Line1, Line2/Circle2/Arc2
|
|
// 2) Circle1, Line2 (converted to case #1)
|
|
// 3) Arc1, Line2 (converted to case #1)
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
if (Geoms[geoId2].type == Line) {
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPerpendicular(l1, l2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else
|
|
std::swap(geoId1, geoId2);
|
|
}
|
|
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Arc || Geoms[geoId2].type == Circle) {
|
|
GCS::Point &p2 = Points[Geoms[geoId2].midPointId];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnLine(p2, l1, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
|
|
Base::Console().Warning("Perpendicular constraints between %s and %s are not supported.\n",
|
|
nameByType(Geoms[geoId1].type), nameByType(Geoms[geoId2].type));
|
|
return -1;
|
|
}
|
|
|
|
// perpendicularity at specific point constraint
|
|
int Sketch::addPerpendicularConstraint(int geoId1, PointPos pos1, int geoId2)
|
|
{
|
|
// accepts the following combinations:
|
|
// 1) Line1, start/end, Line2/Circle2/Arc2
|
|
// 2) Arc1, start/end, Line2/Circle2/Arc2
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
|
|
if (pointId1 < 0 || pointId1 >= int(Points.size()))
|
|
return addPerpendicularConstraint(geoId1, geoId2);
|
|
|
|
GCS::Point &p1 = Points[pointId1];
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Line) {
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnLine(p1, l2, tag);
|
|
GCSsys.addConstraintPerpendicular(l1, l2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
GCS::Point &p2 = Points[Geoms[geoId2].midPointId];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnArc(p1, a2, tag);
|
|
GCSsys.addConstraintPointOnLine(p2, l1, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId2].type == Circle) {
|
|
GCS::Circle &c2 = Circles[Geoms[geoId2].index];
|
|
GCS::Point &p2 = Points[Geoms[geoId2].midPointId];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnCircle(p1, c2, tag);
|
|
GCSsys.addConstraintPointOnLine(p2, l1, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
else if (Geoms[geoId1].type == Arc) {
|
|
GCS::Arc &a1 = Arcs[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Line) {
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnLine(p1, l2, tag);
|
|
GCSsys.addConstraintPointOnLine(a1.center, l2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId2].type == Arc || Geoms[geoId2].type == Circle) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCS::Point ¢er = Points[Geoms[geoId2].midPointId];
|
|
double *radius;
|
|
if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
radius = a2.rad;
|
|
}
|
|
else {
|
|
GCS::Circle &c2 = Circles[Geoms[geoId2].index];
|
|
radius = c2.rad;
|
|
}
|
|
if (pos1 == start)
|
|
GCSsys.addConstraintPerpendicularCircle2Arc(center, radius, a1, tag);
|
|
else if (pos1 == end)
|
|
GCSsys.addConstraintPerpendicularArc2Circle(a1, center, radius, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// perpendicularity at common point constraint
|
|
int Sketch::addPerpendicularConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2)
|
|
{
|
|
// accepts the following combinations:
|
|
// 1) Line1, start/end, Line2/Arc2, start/end
|
|
// 2) Arc1, start/end, Line2, start/end (converted to case #1)
|
|
// 3) Arc1, start/end, Arc2, start/end
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
|
|
if (pointId1 < 0 || pointId1 >= int(Points.size()) ||
|
|
pointId2 < 0 || pointId2 >= int(Points.size()))
|
|
return -1;
|
|
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
if (Geoms[geoId2].type == Line) {
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintP2PCoincident(p1, p2, tag);
|
|
GCSsys.addConstraintPerpendicular(l1, l2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else {
|
|
std::swap(geoId1, geoId2);
|
|
std::swap(pos1, pos2);
|
|
std::swap(pointId1, pointId2);
|
|
p1 = Points[pointId1];
|
|
p2 = Points[pointId2];
|
|
}
|
|
}
|
|
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
if (pos2 == start) {
|
|
if (pos1 == start) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPerpendicularLine2Arc(l1.p2, l1.p1, a2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (pos1 == end) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPerpendicularLine2Arc(l1.p1, l1.p2, a2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
else if (pos2 == end) {
|
|
if (pos1 == start) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPerpendicularArc2Line(a2, l1.p1, l1.p2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (pos1 == end) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPerpendicularArc2Line(a2, l1.p2, l1.p1, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
}
|
|
else if (Geoms[geoId1].type == Arc) {
|
|
GCS::Arc &a1 = Arcs[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
if (pos1 == start && (pos2 == start || pos2 == end)) {
|
|
int tag = ++ConstraintsCounter;
|
|
if (pos2 == start)
|
|
GCSsys.addConstraintPerpendicularArc2Arc(a1, true, a2, false, tag);
|
|
else // if (pos2 == end)
|
|
GCSsys.addConstraintPerpendicularArc2Arc(a1, true, a2, true, tag);
|
|
// GCSsys.addConstraintTangentArc2Arc(a2, false, a1, false, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (pos1 == end && (pos2 == start || pos2 == end)) {
|
|
int tag = ++ConstraintsCounter;
|
|
if (pos2 == start)
|
|
GCSsys.addConstraintPerpendicularArc2Arc(a1, false, a2, false, tag);
|
|
else // if (pos2 == end)
|
|
GCSsys.addConstraintPerpendicularArc2Arc(a1, false, a2, true, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// simple tangency constraint
|
|
int Sketch::addTangentConstraint(int geoId1, int geoId2)
|
|
{
|
|
// accepts the following combinations:
|
|
// 1) Line1, Line2/Circle2/Arc2
|
|
// 2) Circle1, Line2 (converted to case #1)
|
|
// Circle1, Circle2/Arc2
|
|
// 3) Arc1, Line2 (converted to case #1)
|
|
// Arc1, Circle2/Arc2
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
if (Geoms[geoId2].type == Line) {
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
GCS::Point &l2p1 = Points[Geoms[geoId2].startPointId];
|
|
GCS::Point &l2p2 = Points[Geoms[geoId2].endPointId];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnLine(l2p1, l1, tag);
|
|
GCSsys.addConstraintPointOnLine(l2p2, l1, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else
|
|
std::swap(geoId1, geoId2);
|
|
}
|
|
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l = Lines[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a = Arcs[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangent(l, a, tag);
|
|
return ConstraintsCounter;
|
|
} else if (Geoms[geoId2].type == Circle) {
|
|
GCS::Circle &c = Circles[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangent(l, c, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
} else if (Geoms[geoId1].type == Circle) {
|
|
GCS::Circle &c = Circles[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Circle) {
|
|
GCS::Circle &c2 = Circles[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangent(c, c2, tag);
|
|
return ConstraintsCounter;
|
|
} else if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a = Arcs[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangent(c, a, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
} else if (Geoms[geoId1].type == Arc) {
|
|
GCS::Arc &a = Arcs[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Circle) {
|
|
GCS::Circle &c = Circles[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangent(c, a, tag);
|
|
return ConstraintsCounter;
|
|
} else if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangent(a, a2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// tangency at specific point constraint
|
|
int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2)
|
|
{
|
|
// accepts the following combinations:
|
|
// 1) Line1, start/end, Line2/Circle2/Arc2
|
|
// 2) Arc1, start/end, Line2/Circle2/Arc2
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
|
|
if (pointId1 < 0 || pointId1 >= int(Points.size()))
|
|
return addTangentConstraint(geoId1, geoId2);
|
|
|
|
GCS::Point &p1 = Points[pointId1];
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Line) {
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnLine(p1, l2, tag);
|
|
GCSsys.addConstraintParallel(l1, l2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnArc(p1, a2, tag);
|
|
GCSsys.addConstraintTangent(l1, a2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId2].type == Circle) {
|
|
GCS::Circle &c2 = Circles[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnCircle(p1, c2, tag);
|
|
GCSsys.addConstraintTangent(l1, c2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
else if (Geoms[geoId1].type == Arc) {
|
|
GCS::Arc &a1 = Arcs[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Line) {
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnLine(p1, l2, tag);
|
|
GCSsys.addConstraintTangent(l2, a1, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnArc(p1, a2, tag);
|
|
GCSsys.addConstraintTangent(a1, a2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId2].type == Circle) {
|
|
GCS::Circle &c2 = Circles[Geoms[geoId2].index];
|
|
if (pos1 == start) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangentCircle2Arc(c2, a1, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (pos1 == end) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangentArc2Circle(a1, c2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// tangency at common point constraint
|
|
int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2)
|
|
{
|
|
// accepts the following combinations:
|
|
// 1) Line1, start/end, Line2/Arc2, start/end
|
|
// 2) Arc1, start/end, Line2, start/end (converted to case #1)
|
|
// 3) Arc1, start/end, Arc2, start/end
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
|
|
if (pointId1 < 0 || pointId1 >= int(Points.size()) ||
|
|
pointId2 < 0 || pointId2 >= int(Points.size()))
|
|
return -1;
|
|
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
if (Geoms[geoId2].type == Line) {
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintP2PCoincident(p1, p2, tag);
|
|
GCSsys.addConstraintParallel(l1, l2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else {
|
|
std::swap(geoId1, geoId2);
|
|
std::swap(pos1, pos2);
|
|
std::swap(pointId1, pointId2);
|
|
p1 = Points[pointId1];
|
|
p2 = Points[pointId2];
|
|
}
|
|
}
|
|
|
|
if (Geoms[geoId1].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
if (pos2 == start) {
|
|
if (pos1 == start) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangentLine2Arc(l1.p2, l1.p1, a2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (pos1 == end) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangentLine2Arc(l1.p1, l1.p2, a2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
else if (pos2 == end) {
|
|
if (pos1 == start) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangentArc2Line(a2, l1.p1, l1.p2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (pos1 == end) {
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintTangentArc2Line(a2, l1.p2, l1.p1, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
}
|
|
else if (Geoms[geoId1].type == Arc) {
|
|
GCS::Arc &a1 = Arcs[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
if (pos1 == start && (pos2 == start || pos2 == end)) {
|
|
int tag = ++ConstraintsCounter;
|
|
if (pos2 == start)
|
|
GCSsys.addConstraintTangentArc2Arc(a1, true, a2, false, tag);
|
|
else // if (pos2 == end)
|
|
GCSsys.addConstraintTangentArc2Arc(a1, true, a2, true, tag);
|
|
// GCSsys.addConstraintTangentArc2Arc(a2, false, a1, false, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (pos1 == end && (pos2 == start || pos2 == end)) {
|
|
int tag = ++ConstraintsCounter;
|
|
if (pos2 == start)
|
|
GCSsys.addConstraintTangentArc2Arc(a1, false, a2, false, tag);
|
|
else // if (pos2 == end)
|
|
GCSsys.addConstraintTangentArc2Arc(a1, false, a2, true, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// line length constraint
|
|
int Sketch::addDistanceConstraint(int geoId, double value)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
if (Geoms[geoId].type != Line)
|
|
return -1;
|
|
|
|
GCS::Line &l = Lines[Geoms[geoId].index];
|
|
|
|
// add the parameter for the length
|
|
FixParameters.push_back(new double(value));
|
|
double *distance = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintP2PDistance(l.p1, l.p2, distance, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
// line to line distance constraint
|
|
int Sketch::addDistanceConstraint(int geoId1, int geoId2, double value)
|
|
{
|
|
//geoId1 = checkGeoId(geoId1);
|
|
//geoId2 = checkGeoId(geoId2);
|
|
|
|
//assert(Geoms[geoId1].type == Line);
|
|
//assert(Geoms[geoId2].type == Line);
|
|
|
|
Base::Console().Warning("Line to line distance constraints are not implemented yet.\n");
|
|
|
|
return -1;
|
|
}
|
|
|
|
// point to line distance constraint
|
|
int Sketch::addDistanceConstraint(int geoId1, PointPos pos1, int geoId2, double value)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
|
|
if (Geoms[geoId2].type != Line)
|
|
return -1;
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
|
|
// add the parameter for the distance
|
|
FixParameters.push_back(new double(value));
|
|
double *distance = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintP2LDistance(p1, l2, distance, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// point to point distance constraint
|
|
int Sketch::addDistanceConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
|
|
pointId2 >= 0 && pointId2 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
|
|
// add the parameter for the distance
|
|
FixParameters.push_back(new double(value));
|
|
double *distance = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintP2PDistance(p1, p2, distance, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int Sketch::addRadiusConstraint(int geoId, double value)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
if (Geoms[geoId].type == Circle) {
|
|
GCS::Circle &c = Circles[Geoms[geoId].index];
|
|
// add the parameter for the radius
|
|
FixParameters.push_back(new double(value));
|
|
double *radius = FixParameters[FixParameters.size()-1];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintCircleRadius(c, radius, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId].type == Arc) {
|
|
GCS::Arc &a = Arcs[Geoms[geoId].index];
|
|
// add the parameter for the radius
|
|
FixParameters.push_back(new double(value));
|
|
double *radius = FixParameters[FixParameters.size()-1];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintArcRadius(a, radius, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// line orientation angle constraint
|
|
int Sketch::addAngleConstraint(int geoId, double value)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
if (Geoms[geoId].type != Line)
|
|
return -1;
|
|
|
|
GCS::Line &l = Lines[Geoms[geoId].index];
|
|
|
|
// add the parameter for the angle
|
|
FixParameters.push_back(new double(value));
|
|
double *angle = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintP2PAngle(l.p1, l.p2, angle, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
// line to line angle constraint
|
|
int Sketch::addAngleConstraint(int geoId1, int geoId2, double value)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
if (Geoms[geoId1].type != Line ||
|
|
Geoms[geoId2].type != Line)
|
|
return -1;
|
|
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
|
|
// add the parameter for the angle
|
|
FixParameters.push_back(new double(value));
|
|
double *angle = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintL2LAngle(l1, l2, angle, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
// line to line angle constraint (with explicitly given start points)
|
|
int Sketch::addAngleConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
if (Geoms[geoId1].type != Line ||
|
|
Geoms[geoId2].type != Line)
|
|
return -1;
|
|
|
|
GCS::Point *l1p1=0, *l1p2=0;
|
|
if (pos1 == start) {
|
|
l1p1 = &Points[Geoms[geoId1].startPointId];
|
|
l1p2 = &Points[Geoms[geoId1].endPointId];
|
|
} else if (pos1 == end) {
|
|
l1p1 = &Points[Geoms[geoId1].endPointId];
|
|
l1p2 = &Points[Geoms[geoId1].startPointId];
|
|
}
|
|
|
|
GCS::Point *l2p1=0, *l2p2=0;
|
|
if (pos2 == start) {
|
|
l2p1 = &Points[Geoms[geoId2].startPointId];
|
|
l2p2 = &Points[Geoms[geoId2].endPointId];
|
|
} else if (pos2 == end) {
|
|
l2p1 = &Points[Geoms[geoId2].endPointId];
|
|
l2p2 = &Points[Geoms[geoId2].startPointId];
|
|
}
|
|
|
|
if (l1p1 == 0 || l2p1 == 0)
|
|
return -1;
|
|
|
|
// add the parameter for the angle
|
|
FixParameters.push_back(new double(value));
|
|
double *angle = FixParameters[FixParameters.size()-1];
|
|
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintL2LAngle(*l1p1, *l1p2, *l2p1, *l2p2, angle, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
int Sketch::addEqualConstraint(int geoId1, int geoId2)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
if (Geoms[geoId1].type == Line &&
|
|
Geoms[geoId2].type == Line) {
|
|
GCS::Line &l1 = Lines[Geoms[geoId1].index];
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
double dx1 = (*l1.p2.x - *l1.p1.x);
|
|
double dy1 = (*l1.p2.y - *l1.p1.y);
|
|
double dx2 = (*l2.p2.x - *l2.p1.x);
|
|
double dy2 = (*l2.p2.y - *l2.p1.y);
|
|
double value = (sqrt(dx1*dx1+dy1*dy1)+sqrt(dx2*dx2+dy2*dy2))/2;
|
|
// add the parameter for the common length (this is added to Parameters, not FixParameters)
|
|
Parameters.push_back(new double(value));
|
|
double *length = Parameters[Parameters.size()-1];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintEqualLength(l1, l2, length, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
if (Geoms[geoId2].type == Circle) {
|
|
if (Geoms[geoId1].type == Circle) {
|
|
GCS::Circle &c1 = Circles[Geoms[geoId1].index];
|
|
GCS::Circle &c2 = Circles[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintEqualRadius(c1, c2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else
|
|
std::swap(geoId1, geoId2);
|
|
}
|
|
|
|
if (Geoms[geoId1].type == Circle) {
|
|
GCS::Circle &c1 = Circles[Geoms[geoId1].index];
|
|
if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintEqualRadius(c1, a2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
|
|
if (Geoms[geoId1].type == Arc &&
|
|
Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a1 = Arcs[Geoms[geoId1].index];
|
|
GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintEqualRadius(a1, a2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
|
|
Base::Console().Warning("Equality constraints between %s and %s are not supported.\n",
|
|
nameByType(Geoms[geoId1].type), nameByType(Geoms[geoId2].type));
|
|
return -1;
|
|
}
|
|
|
|
// point on object constraint
|
|
int Sketch::addPointOnObjectConstraint(int geoId1, PointPos pos1, int geoId2)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
|
|
if (Geoms[geoId2].type == Line) {
|
|
GCS::Line &l2 = Lines[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnLine(p1, l2, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId2].type == Arc) {
|
|
GCS::Arc &a = Arcs[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnArc(p1, a, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
else if (Geoms[geoId2].type == Circle) {
|
|
GCS::Circle &c = Circles[Geoms[geoId2].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintPointOnCircle(p1, c, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// symmetric points constraint
|
|
int Sketch::addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, int geoId3)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
geoId3 = checkGeoId(geoId3);
|
|
|
|
if (Geoms[geoId3].type != Line)
|
|
return -1;
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
|
|
pointId2 >= 0 && pointId2 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
GCS::Line &l = Lines[Geoms[geoId3].index];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintP2PSymmetric(p1, p2, l, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int Sketch::addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2,
|
|
int geoId3, PointPos pos3)
|
|
{
|
|
geoId1 = checkGeoId(geoId1);
|
|
geoId2 = checkGeoId(geoId2);
|
|
geoId3 = checkGeoId(geoId3);
|
|
|
|
int pointId1 = getPointId(geoId1, pos1);
|
|
int pointId2 = getPointId(geoId2, pos2);
|
|
int pointId3 = getPointId(geoId3, pos3);
|
|
|
|
if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
|
|
pointId2 >= 0 && pointId2 < int(Points.size()) &&
|
|
pointId3 >= 0 && pointId3 < int(Points.size())) {
|
|
GCS::Point &p1 = Points[pointId1];
|
|
GCS::Point &p2 = Points[pointId2];
|
|
GCS::Point &p = Points[pointId3];
|
|
int tag = ++ConstraintsCounter;
|
|
GCSsys.addConstraintP2PSymmetric(p1, p2, p, tag);
|
|
return ConstraintsCounter;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
bool Sketch::updateGeometry()
|
|
{
|
|
int i=0;
|
|
for (std::vector<GeoDef>::const_iterator it=Geoms.begin(); it != Geoms.end(); ++it, i++) {
|
|
try {
|
|
if (it->type == Point) {
|
|
GeomPoint *point = dynamic_cast<GeomPoint*>(it->geo);
|
|
point->setPoint(Vector3d(*Points[it->startPointId].x,
|
|
*Points[it->startPointId].y,
|
|
0.0)
|
|
);
|
|
} else if (it->type == Line) {
|
|
GeomLineSegment *lineSeg = dynamic_cast<GeomLineSegment*>(it->geo);
|
|
lineSeg->setPoints(Vector3d(*Lines[it->index].p1.x,
|
|
*Lines[it->index].p1.y,
|
|
0.0),
|
|
Vector3d(*Lines[it->index].p2.x,
|
|
*Lines[it->index].p2.y,
|
|
0.0)
|
|
);
|
|
} else if (it->type == Arc) {
|
|
GCS::Arc &myArc = Arcs[it->index];
|
|
// the following 4 lines are redundant since these equations are already included in the arc constraints
|
|
// *myArc.start.x = *myArc.center.x + *myArc.rad * cos(*myArc.startAngle);
|
|
// *myArc.start.y = *myArc.center.y + *myArc.rad * sin(*myArc.startAngle);
|
|
// *myArc.end.x = *myArc.center.x + *myArc.rad * cos(*myArc.endAngle);
|
|
// *myArc.end.y = *myArc.center.y + *myArc.rad * sin(*myArc.endAngle);
|
|
GeomArcOfCircle *aoc = dynamic_cast<GeomArcOfCircle*>(it->geo);
|
|
aoc->setCenter(Vector3d(*Points[it->midPointId].x,
|
|
*Points[it->midPointId].y,
|
|
0.0)
|
|
);
|
|
aoc->setRadius(*myArc.rad);
|
|
aoc->setRange(*myArc.startAngle, *myArc.endAngle);
|
|
} else if (it->type == Circle) {
|
|
GeomCircle *circ = dynamic_cast<GeomCircle*>(it->geo);
|
|
circ->setCenter(Vector3d(*Points[it->midPointId].x,
|
|
*Points[it->midPointId].y,
|
|
0.0)
|
|
);
|
|
circ->setRadius(*Circles[it->index].rad);
|
|
}
|
|
} catch (Base::Exception e) {
|
|
Base::Console().Error("Updating geometry: Error build geometry(%d): %s\n",
|
|
i,e.what());
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// solving ==========================================================
|
|
|
|
int Sketch::solve(void)
|
|
{
|
|
|
|
Base::TimeInfo start_time;
|
|
if (!isInitMove) { // make sure we are in single subsystem mode
|
|
GCSsys.clearByTag(-1);
|
|
isFine = true;
|
|
}
|
|
|
|
int ret;
|
|
bool valid_solution;
|
|
for (int soltype=0; soltype < (isInitMove ? 1 : 4); soltype++) {
|
|
std::string solvername;
|
|
switch (soltype) {
|
|
case 0: // solving with the default DogLeg solver
|
|
// (or with SQP if we are in moving mode)
|
|
solvername = isInitMove ? "SQP" : "DogLeg";
|
|
ret = GCSsys.solve(isFine, GCS::DogLeg);
|
|
break;
|
|
case 1: // solving with the LevenbergMarquardt solver
|
|
solvername = "LevenbergMarquardt";
|
|
ret = GCSsys.solve(isFine, GCS::LevenbergMarquardt);
|
|
break;
|
|
case 2: // solving with the BFGS solver
|
|
solvername = "BFGS";
|
|
ret = GCSsys.solve(isFine, GCS::BFGS);
|
|
break;
|
|
case 3: // last resort: augment the system with a second subsystem and use the SQP solver
|
|
solvername = "SQP(augmented system)";
|
|
InitParameters.resize(Parameters.size());
|
|
int i=0;
|
|
for (std::vector<double*>::iterator it = Parameters.begin(); it != Parameters.end(); ++it, i++) {
|
|
InitParameters[i] = **it;
|
|
GCSsys.addConstraintEqual(*it, &InitParameters[i], -1);
|
|
}
|
|
GCSsys.initSolution();
|
|
ret = GCSsys.solve(isFine);
|
|
break;
|
|
}
|
|
|
|
// if successfully solved try to write the parameters back
|
|
if (ret == GCS::Success) {
|
|
GCSsys.applySolution();
|
|
valid_solution = updateGeometry();
|
|
if (!valid_solution) {
|
|
GCSsys.undoSolution();
|
|
updateGeometry();
|
|
Base::Console().Warning("Invalid solution from %s solver.\n", solvername.c_str());
|
|
}
|
|
} else {
|
|
valid_solution = false;
|
|
//Base::Console().Log("NotSolved ");
|
|
}
|
|
|
|
if (soltype == 3) // cleanup temporary constraints of the augmented system
|
|
GCSsys.clearByTag(-1);
|
|
|
|
if (valid_solution) {
|
|
if (soltype == 1)
|
|
Base::Console().Log("Important: the LevenbergMarquardt solver succeeded where the DogLeg solver had failed.\n");
|
|
else if (soltype == 2)
|
|
Base::Console().Log("Important: the BFGS solver succeeded where the DogLeg and LevenbergMarquardt solvers have failed.\n");
|
|
else if (soltype == 3)
|
|
Base::Console().Log("Important: the SQP solver succeeded where all single subsystem solvers have failed.\n");
|
|
|
|
if (soltype > 0) {
|
|
Base::Console().Log("If you see this message please report a way of reproducing this result at\n");
|
|
Base::Console().Log("http://www.freecadweb.org/tracker/main_page.php\n");
|
|
}
|
|
|
|
break;
|
|
}
|
|
} // soltype
|
|
|
|
Base::TimeInfo end_time;
|
|
//Base::Console().Log("T:%s\n",Base::TimeInfo::diffTime(start_time,end_time).c_str());
|
|
SolveTime = Base::TimeInfo::diffTimeF(start_time,end_time);
|
|
return ret;
|
|
}
|
|
|
|
int Sketch::initMove(int geoId, PointPos pos, bool fine)
|
|
{
|
|
isFine = fine;
|
|
|
|
geoId = checkGeoId(geoId);
|
|
|
|
GCSsys.clearByTag(-1);
|
|
|
|
// don't try to move sketches that contain conflicting constraints
|
|
if (hasConflicts()) {
|
|
isInitMove = false;
|
|
return -1;
|
|
}
|
|
|
|
if (Geoms[geoId].type == Point) {
|
|
if (pos == start) {
|
|
GCS::Point &point = Points[Geoms[geoId].startPointId];
|
|
GCS::Point p0;
|
|
MoveParameters.resize(2); // px,py
|
|
p0.x = &MoveParameters[0];
|
|
p0.y = &MoveParameters[1];
|
|
*p0.x = *point.x;
|
|
*p0.y = *point.y;
|
|
GCSsys.addConstraintP2PCoincident(p0,point,-1);
|
|
}
|
|
} else if (Geoms[geoId].type == Line) {
|
|
if (pos == start || pos == end) {
|
|
MoveParameters.resize(2); // x,y
|
|
GCS::Point p0;
|
|
p0.x = &MoveParameters[0];
|
|
p0.y = &MoveParameters[1];
|
|
if (pos == start) {
|
|
GCS::Point &p = Points[Geoms[geoId].startPointId];
|
|
*p0.x = *p.x;
|
|
*p0.y = *p.y;
|
|
GCSsys.addConstraintP2PCoincident(p0,p,-1);
|
|
} else if (pos == end) {
|
|
GCS::Point &p = Points[Geoms[geoId].endPointId];
|
|
*p0.x = *p.x;
|
|
*p0.y = *p.y;
|
|
GCSsys.addConstraintP2PCoincident(p0,p,-1);
|
|
}
|
|
} else if (pos == none || pos == mid) {
|
|
MoveParameters.resize(4); // x1,y1,x2,y2
|
|
GCS::Point p1, p2;
|
|
p1.x = &MoveParameters[0];
|
|
p1.y = &MoveParameters[1];
|
|
p2.x = &MoveParameters[2];
|
|
p2.y = &MoveParameters[3];
|
|
GCS::Line &l = Lines[Geoms[geoId].index];
|
|
*p1.x = *l.p1.x;
|
|
*p1.y = *l.p1.y;
|
|
*p2.x = *l.p2.x;
|
|
*p2.y = *l.p2.y;
|
|
GCSsys.addConstraintP2PCoincident(p1,l.p1,-1);
|
|
GCSsys.addConstraintP2PCoincident(p2,l.p2,-1);
|
|
}
|
|
} else if (Geoms[geoId].type == Circle) {
|
|
GCS::Point ¢er = Points[Geoms[geoId].midPointId];
|
|
GCS::Point p0,p1;
|
|
if (pos == mid) {
|
|
MoveParameters.resize(2); // cx,cy
|
|
p0.x = &MoveParameters[0];
|
|
p0.y = &MoveParameters[1];
|
|
*p0.x = *center.x;
|
|
*p0.y = *center.y;
|
|
GCSsys.addConstraintP2PCoincident(p0,center,-1);
|
|
} else if (pos == none) {
|
|
MoveParameters.resize(4); // x,y,cx,cy
|
|
GCS::Circle &c = Circles[Geoms[geoId].index];
|
|
p0.x = &MoveParameters[0];
|
|
p0.y = &MoveParameters[1];
|
|
*p0.x = *center.x;
|
|
*p0.y = *center.y + *c.rad;
|
|
GCSsys.addConstraintPointOnCircle(p0,c,-1);
|
|
p1.x = &MoveParameters[2];
|
|
p1.y = &MoveParameters[3];
|
|
*p1.x = *center.x;
|
|
*p1.y = *center.y;
|
|
int i=GCSsys.addConstraintP2PCoincident(p1,center,-1);
|
|
GCSsys.rescaleConstraint(i-1, 0.01);
|
|
GCSsys.rescaleConstraint(i, 0.01);
|
|
}
|
|
} else if (Geoms[geoId].type == Arc) {
|
|
GCS::Point ¢er = Points[Geoms[geoId].midPointId];
|
|
GCS::Point p0,p1;
|
|
if (pos == mid) {
|
|
MoveParameters.resize(2); // cx,cy
|
|
p0.x = &MoveParameters[0];
|
|
p0.y = &MoveParameters[1];
|
|
*p0.x = *center.x;
|
|
*p0.y = *center.y;
|
|
GCSsys.addConstraintP2PCoincident(p0,center,-1);
|
|
} else if (pos == start || pos == end || pos == none) {
|
|
MoveParameters.resize(4); // x,y,cx,cy
|
|
if (pos == start || pos == end) {
|
|
GCS::Point &p = (pos == start) ? Points[Geoms[geoId].startPointId]
|
|
: Points[Geoms[geoId].endPointId];;
|
|
p0.x = &MoveParameters[0];
|
|
p0.y = &MoveParameters[1];
|
|
*p0.x = *p.x;
|
|
*p0.y = *p.y;
|
|
GCSsys.addConstraintP2PCoincident(p0,p,-1);
|
|
} else if (pos == none) {
|
|
GCS::Arc &a = Arcs[Geoms[geoId].index];
|
|
p0.x = &MoveParameters[0];
|
|
p0.y = &MoveParameters[1];
|
|
*p0.x = *center.x;
|
|
*p0.y = *center.y + *a.rad;
|
|
GCSsys.addConstraintPointOnArc(p0,a,-1);
|
|
}
|
|
p1.x = &MoveParameters[2];
|
|
p1.y = &MoveParameters[3];
|
|
*p1.x = *center.x;
|
|
*p1.y = *center.y;
|
|
int i=GCSsys.addConstraintP2PCoincident(p1,center,-1);
|
|
GCSsys.rescaleConstraint(i-1, 0.01);
|
|
GCSsys.rescaleConstraint(i, 0.01);
|
|
}
|
|
}
|
|
InitParameters = MoveParameters;
|
|
|
|
GCSsys.initSolution();
|
|
isInitMove = true;
|
|
return 0;
|
|
}
|
|
|
|
int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
|
|
// don't try to move sketches that contain conflicting constraints
|
|
if (hasConflicts())
|
|
return -1;
|
|
|
|
if (!isInitMove)
|
|
initMove(geoId, pos);
|
|
|
|
if (relative) {
|
|
for (int i=0; i < int(MoveParameters.size()-1); i+=2) {
|
|
MoveParameters[i] = InitParameters[i] + toPoint.x;
|
|
MoveParameters[i+1] = InitParameters[i+1] + toPoint.y;
|
|
}
|
|
} else if (Geoms[geoId].type == Point) {
|
|
if (pos == start) {
|
|
MoveParameters[0] = toPoint.x;
|
|
MoveParameters[1] = toPoint.y;
|
|
}
|
|
} else if (Geoms[geoId].type == Line) {
|
|
if (pos == start || pos == end) {
|
|
MoveParameters[0] = toPoint.x;
|
|
MoveParameters[1] = toPoint.y;
|
|
} else if (pos == none || pos == mid) {
|
|
double dx = (InitParameters[2]-InitParameters[0])/2;
|
|
double dy = (InitParameters[3]-InitParameters[1])/2;
|
|
MoveParameters[0] = toPoint.x - dx;
|
|
MoveParameters[1] = toPoint.y - dy;
|
|
MoveParameters[2] = toPoint.x + dx;
|
|
MoveParameters[3] = toPoint.y + dy;
|
|
}
|
|
} else if (Geoms[geoId].type == Circle) {
|
|
if (pos == mid || pos == none) {
|
|
MoveParameters[0] = toPoint.x;
|
|
MoveParameters[1] = toPoint.y;
|
|
}
|
|
} else if (Geoms[geoId].type == Arc) {
|
|
if (pos == start || pos == end || pos == mid || pos == none) {
|
|
MoveParameters[0] = toPoint.x;
|
|
MoveParameters[1] = toPoint.y;
|
|
}
|
|
}
|
|
|
|
return solve();
|
|
}
|
|
|
|
int Sketch::setDatum(int constrId, double value)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int Sketch::getPointId(int geoId, PointPos pos) const
|
|
{
|
|
// do a range check first
|
|
if (geoId < 0 || geoId >= (int)Geoms.size())
|
|
return -1;
|
|
switch (pos) {
|
|
case start:
|
|
return Geoms[geoId].startPointId;
|
|
case end:
|
|
return Geoms[geoId].endPointId;
|
|
case mid:
|
|
return Geoms[geoId].midPointId;
|
|
case none:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
Base::Vector3d Sketch::getPoint(int geoId, PointPos pos)
|
|
{
|
|
geoId = checkGeoId(geoId);
|
|
int pointId = getPointId(geoId, pos);
|
|
if (pointId != -1)
|
|
return Base::Vector3d(*Points[pointId].x, *Points[pointId].y, 0);
|
|
|
|
return Base::Vector3d();
|
|
}
|
|
|
|
|
|
|
|
TopoShape Sketch::toShape(void) const
|
|
{
|
|
TopoShape result;
|
|
std::vector<GeoDef>::const_iterator it=Geoms.begin();
|
|
|
|
#if 0
|
|
|
|
bool first = true;
|
|
for (;it!=Geoms.end();++it) {
|
|
if (!it->geo->Construction) {
|
|
TopoDS_Shape sh = it->geo->toShape();
|
|
if (first) {
|
|
first = false;
|
|
result._Shape = sh;
|
|
} else {
|
|
result._Shape = result.fuse(sh);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
#else
|
|
std::list<TopoDS_Edge> edge_list;
|
|
std::list<TopoDS_Wire> wires;
|
|
|
|
// collecting all (non constructive and non external) edges out of the sketch
|
|
for (;it!=Geoms.end();++it) {
|
|
if (!it->external && !it->geo->Construction) {
|
|
edge_list.push_back(TopoDS::Edge(it->geo->toShape()));
|
|
}
|
|
}
|
|
|
|
// FIXME: Use ShapeAnalysis_FreeBounds::ConnectEdgesToWires() as an alternative
|
|
//
|
|
// sort them together to wires
|
|
while (edge_list.size() > 0) {
|
|
BRepBuilderAPI_MakeWire mkWire;
|
|
// add and erase first edge
|
|
mkWire.Add(edge_list.front());
|
|
edge_list.pop_front();
|
|
|
|
TopoDS_Wire new_wire = mkWire.Wire(); // current new wire
|
|
|
|
// try to connect each edge to the wire, the wire is complete if no more egdes are connectible
|
|
bool found = false;
|
|
do {
|
|
found = false;
|
|
for (std::list<TopoDS_Edge>::iterator pE = edge_list.begin(); pE != edge_list.end(); ++pE) {
|
|
mkWire.Add(*pE);
|
|
if (mkWire.Error() != BRepBuilderAPI_DisconnectedWire) {
|
|
// edge added ==> remove it from list
|
|
found = true;
|
|
edge_list.erase(pE);
|
|
new_wire = mkWire.Wire();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (found);
|
|
|
|
// Fix any topological issues of the wire
|
|
ShapeFix_Wire aFix;
|
|
aFix.SetPrecision(Precision::Confusion());
|
|
aFix.Load(new_wire);
|
|
aFix.FixReorder();
|
|
aFix.FixConnected();
|
|
aFix.FixClosed();
|
|
wires.push_back(aFix.Wire());
|
|
}
|
|
if (wires.size() == 1)
|
|
result = *wires.begin();
|
|
else if (wires.size() > 1) {
|
|
// FIXME: The right way here would be to determine the outer and inner wires and
|
|
// generate a face with holes (inner wires have to be taged REVERSE or INNER).
|
|
// thats the only way to transport a somwhat more complex sketch...
|
|
//result = *wires.begin();
|
|
|
|
// I think a compound can be used as container because it is just a collection of
|
|
// shapes and doesn't need too much information about the topology.
|
|
// The actual knowledge how to create a prism from several wires should go to the Pad
|
|
// feature (Werner).
|
|
BRep_Builder builder;
|
|
TopoDS_Compound comp;
|
|
builder.MakeCompound(comp);
|
|
for (std::list<TopoDS_Wire>::iterator wt = wires.begin(); wt != wires.end(); ++wt)
|
|
builder.Add(comp, *wt);
|
|
result._Shape = comp;
|
|
}
|
|
// FIXME: if free edges are left over its probably better to
|
|
// create a compound with the closed structures and let the
|
|
// features decide what to do with it...
|
|
if (edge_list.size() > 0)
|
|
Base::Console().Warning("Left over edges in Sketch. Only closed structures will be propagated at the moment!\n");
|
|
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
// Persistance implementer -------------------------------------------------
|
|
|
|
unsigned int Sketch::getMemSize(void) const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void Sketch::Save(Writer &writer) const
|
|
{
|
|
|
|
}
|
|
|
|
void Sketch::Restore(XMLReader &reader)
|
|
{
|
|
|
|
}
|
|
|