/*************************************************************************** * Copyright (c) 2010 Jürgen Riegel * * * * 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 # include # include # include # include #endif /// Here the FreeCAD includes sorted by Base,App,Gui...... #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DrawSketchHandler.h" #include "ViewProviderSketch.h" using namespace SketcherGui; using namespace Sketcher; //************************************************************************** // Construction/Destruction DrawSketchHandler::DrawSketchHandler() : sketchgui(0) { } DrawSketchHandler::~DrawSketchHandler() { } void DrawSketchHandler::quit(void) { assert(sketchgui); sketchgui->drawEdit(std::vector()); resetPositionText(); unsetCursor(); sketchgui->purgeHandler(); } //************************************************************************** // Helpers int DrawSketchHandler::getHighestVertexIndex(void) { return sketchgui->getSketchObject()->getHighestVertexIndex(); } int DrawSketchHandler::getHighestCurveIndex(void) { return sketchgui->getSketchObject()->getHighestCurveIndex(); } void DrawSketchHandler::setCursor(const QPixmap &p,int x,int y) { Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { Gui::View3DInventorViewer* viewer = static_cast(view)->getViewer(); oldCursor = viewer->getWidget()->cursor(); QCursor cursor(p, x, y); actCursor = cursor; viewer->getWidget()->setCursor(cursor); } } void DrawSketchHandler::applyCursor(void) { applyCursor(actCursor); } void DrawSketchHandler::applyCursor(QCursor &newCursor) { Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { Gui::View3DInventorViewer* viewer = static_cast(view)->getViewer(); viewer->getWidget()->setCursor(newCursor); } } void DrawSketchHandler::unsetCursor(void) { Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { Gui::View3DInventorViewer* viewer = static_cast(view)->getViewer(); viewer->getWidget()->setCursor(oldCursor); } } int DrawSketchHandler::seekAutoConstraint(std::vector &suggestedConstraints, const Base::Vector2D& Pos, const Base::Vector2D& Dir, AutoConstraint::TargetType type) { suggestedConstraints.clear(); if (!sketchgui->Autoconstraints.getValue()) return 0; // If Autoconstraints property is not set quit // Get Preselection int preSelPnt = sketchgui->getPreselectPoint(); int preSelCrv = sketchgui->getPreselectCurve(); int preSelCrs = sketchgui->getPreselectCross(); int GeoId = Constraint::GeoUndef; Sketcher::PointPos PosId = Sketcher::none; if (preSelPnt != -1) sketchgui->getSketchObject()->getGeoVertexIndex(preSelPnt, GeoId, PosId); else if (preSelCrv != -1) GeoId = preSelCrv; else if (preSelCrs == 0) { // root point GeoId = -1; PosId = Sketcher::start; } else if (preSelCrs == 1) // x axis GeoId = -1; else if (preSelCrs == 2) // y axis GeoId = -2; if (GeoId != Constraint::GeoUndef) { // Currently only considers objects in current Sketcher AutoConstraint constr; constr.Type = Sketcher::None; constr.GeoId = GeoId; constr.PosId = PosId; if (type == AutoConstraint::VERTEX && PosId != Sketcher::none) constr.Type = Sketcher::Coincident; else if (type == AutoConstraint::CURVE && PosId != Sketcher::none) constr.Type = Sketcher::PointOnObject; else if (type == AutoConstraint::VERTEX && PosId == Sketcher::none) constr.Type = Sketcher::PointOnObject; else if (type == AutoConstraint::CURVE && PosId == Sketcher::none) constr.Type = Sketcher::Tangent; if (constr.Type != Sketcher::None) suggestedConstraints.push_back(constr); } if (Dir.Length() < 1e-8) // Direction not set so return; return suggestedConstraints.size(); // Suggest vertical and horizontal constraints // Number of Degree of deviation from horizontal or vertical lines const double angleDev = 2; const double angleDevRad = angleDev * M_PI / 180.; AutoConstraint constr; constr.Type = Sketcher::None; constr.GeoId = Constraint::GeoUndef; constr.PosId = Sketcher::none; double angle = std::abs(atan2(Dir.fY, Dir.fX)); if (angle < angleDevRad || (M_PI - angle) < angleDevRad ) // Suggest horizontal constraint constr.Type = Sketcher::Horizontal; else if (std::abs(angle - M_PI_2) < angleDevRad) // Suggest vertical constraint constr.Type = Sketcher::Vertical; if (constr.Type != Sketcher::None) suggestedConstraints.push_back(constr); // Find if there are tangent constraints (currently arcs and circles) int tangId = Constraint::GeoUndef; // Do not consider if distance is more than that. // Decrease this value when a candidate is found. double tangDeviation = 0.1 * sketchgui->getScaleFactor(); // Get geometry list const std::vector geomlist = sketchgui->getSketchObject()->getCompleteGeometry(); Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f); // Current cursor point Base::Vector3d tmpDir(Dir.fX, Dir.fY, 0.f); // Direction of line Base::Vector3d tmpStart(Pos.fX-Dir.fX, Pos.fY-Dir.fY, 0.f); // Start point // Iterate through geometry int i = 0; for (std::vector::const_iterator it=geomlist.begin(); it != geomlist.end(); ++it, i++) { if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) { const Part::GeomCircle *circle = dynamic_cast((*it)); Base::Vector3d center = circle->getCenter(); double radius = circle->getRadius(); // ignore if no touch (use dot product) if(tmpDir * (center-tmpPos) > 0 || tmpDir * (center-tmpStart) < 0) continue; Base::Vector3d projPnt(0.f, 0.f, 0.f); projPnt = projPnt.ProjToLine(center - tmpPos, tmpDir); double projDist = std::abs(projPnt.Length() - radius); // Find if nearest if (projDist < tangDeviation) { tangId = i; tangDeviation = projDist; } } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *arc = dynamic_cast((*it)); Base::Vector3d center = arc->getCenter(); double radius = arc->getRadius(); // ignore if no touch (use dot product) if(tmpDir * (center-tmpPos) > 0 || tmpDir * (center-tmpStart) < 0) continue; Base::Vector3d projPnt(0.f, 0.f, 0.f); projPnt = projPnt.ProjToLine(center - tmpPos, tmpDir); double projDist = std::abs(projPnt.Length() - radius); if (projDist < tangDeviation) { double startAngle, endAngle; arc->getRange(startAngle, endAngle); double angle = atan2(projPnt.y, projPnt.x); 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 = projDist; } } } } if (tangId != Constraint::GeoUndef) { if (tangId > getHighestCurveIndex()) // external Geometry tangId = getHighestCurveIndex() - tangId; // Suggest vertical constraint constr.Type = Tangent; constr.GeoId = tangId; constr.PosId = Sketcher::none; suggestedConstraints.push_back(constr); } return suggestedConstraints.size(); } void DrawSketchHandler::createAutoConstraints(const std::vector &autoConstrs, int geoId1, Sketcher::PointPos posId1) { if (!sketchgui->Autoconstraints.getValue()) return; // If Autoconstraints property is not set quit if (autoConstrs.size() > 0) { // Open the Command Gui::Command::openCommand("Add auto constraints"); // Iterate through constraints std::vector::const_iterator it = autoConstrs.begin(); for (; it != autoConstrs.end(); ++it) { switch (it->Type) { case Sketcher::Coincident: { if (posId1 == Sketcher::none) continue; // If the auto constraint has a point create a coincident otherwise it is an edge on a point Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Coincident',%i,%i,%i,%i)) " ,sketchgui->getObject()->getNameInDocument() ,geoId1, posId1, it->GeoId, it->PosId ); } break; case Sketcher::PointOnObject: { int geoId2 = it->GeoId; Sketcher::PointPos posId2 = it->PosId; if (posId1 == Sketcher::none) { // Auto constraining an edge so swap parameters std::swap(geoId1,geoId2); std::swap(posId1,posId2); } Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%i,%i,%i)) " ,sketchgui->getObject()->getNameInDocument() ,geoId1, posId1, geoId2 ); } break; case Sketcher::Horizontal: { Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Horizontal',%i)) " ,sketchgui->getObject()->getNameInDocument() ,geoId1 ); } break; case Sketcher::Vertical: { Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Vertical',%i)) " ,sketchgui->getObject()->getNameInDocument() ,geoId1 ); } break; case Sketcher::Tangent: { Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%i, %i)) " ,sketchgui->getObject()->getNameInDocument() ,geoId1, it->GeoId ); } break; default: break; } Gui::Command::commitCommand(); Gui::Command::updateActive(); } } } void DrawSketchHandler::renderSuggestConstraintsCursor(std::vector &suggestedConstraints) { // Auto Constrait icon size in px int iconSize = 16; // Create a pixmap that will contain icon and each autoconstraint icon QPixmap baseIcon = actCursor.pixmap(); QPixmap newIcon(baseIcon.width() + suggestedConstraints.size() * iconSize, baseIcon.height()); newIcon.fill(Qt::transparent); QPainter qp; qp.begin(&newIcon); qp.drawPixmap(0,0, baseIcon); // Iterate through AutoConstraints type and add icons to the cursor pixmap std::vector::iterator it=suggestedConstraints.begin(); int i = 0; for (; it != suggestedConstraints.end(); ++it, i++) { QString iconType; switch (it->Type) { case Horizontal: iconType = QString::fromAscii("Constraint_Horizontal"); break; case Vertical: iconType = QString::fromAscii("Constraint_Vertical"); break; case Coincident: iconType = QString::fromAscii("Constraint_PointOnPoint"); break; case PointOnObject: iconType = QString::fromAscii("Constraint_PointOnObject"); break; case Tangent: iconType = QString::fromAscii("Constraint_Tangent"); break; default: break; } if (!iconType.isEmpty()) { QPixmap icon = Gui::BitmapFactory().pixmap(iconType.toAscii()).scaledToWidth(iconSize); qp.drawPixmap(QPoint(baseIcon.width() + i * iconSize, baseIcon.height() - iconSize), icon); } } qp.end(); // Finish painting // Create the new cursor with the icon. QPoint p=actCursor.hotSpot(); QCursor newCursor(newIcon, p.x(), p.y()); applyCursor(newCursor); } void DrawSketchHandler::setPositionText(const Base::Vector2D &Pos, const SbString &text) { sketchgui->setPositionText(Pos, text); } void DrawSketchHandler::setPositionText(const Base::Vector2D &Pos) { sketchgui->setPositionText(Pos); } void DrawSketchHandler::resetPositionText(void) { sketchgui->resetPositionText(); }