/*************************************************************************** * Copyright (c) 2013 Werner Mayer * * * * 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 # include # include # include # include # include #endif #include #include #include #include #include "ui_TaskSketcherValidation.h" #include "TaskSketcherValidation.h" #include #include #include #include #include #include #include using namespace SketcherGui; using namespace Gui::TaskView; /* TRANSLATOR SketcherGui::SketcherValidation */ SketcherValidation::SketcherValidation(Sketcher::SketchObject* Obj, QWidget* parent) : QWidget(parent), ui(new Ui_TaskSketcherValidation()), sketch(Obj), coincidenceRoot(0) { ui->setupUi(this); ui->fixButton->setEnabled(false); double tolerances[8] = { Precision::Confusion() / 100, Precision::Confusion() / 10, Precision::Confusion(), Precision::Confusion() * 10, Precision::Confusion() * 100, Precision::Confusion() * 1000, Precision::Confusion() * 10000, Precision::Confusion() * 100000 }; for (int i=0; i<8; i++) { ui->comboBoxTolerance->addItem(QLocale::system().toString(tolerances[i]), QVariant(tolerances[i])); } ui->comboBoxTolerance->setCurrentIndex(5); ui->comboBoxTolerance->setEditable(true); ui->comboBoxTolerance->setValidator(new QDoubleValidator(0,10,10,this)); } SketcherValidation::~SketcherValidation() { hidePoints(); } void SketcherValidation::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } QWidget::changeEvent(e); } struct SketcherValidation::VertexIds { Base::Vector3d v; int GeoId; Sketcher::PointPos PosId; }; struct SketcherValidation::Vertex_Less : public std::binary_function { Vertex_Less(double tolerance) : tolerance(tolerance){} bool operator()(const VertexIds& x, const VertexIds& y) const { if (fabs (x.v.x - y.v.x) > tolerance) return x.v.x < y.v.x; if (fabs (x.v.y - y.v.y) > tolerance) return x.v.y < y.v.y; if (fabs (x.v.z - y.v.z) > tolerance) return x.v.z < y.v.z; return false; // points are considered to be equal } private: double tolerance; }; struct SketcherValidation::Vertex_EqualTo : public std::binary_function { Vertex_EqualTo(double tolerance) : tolerance(tolerance){} bool operator()(const VertexIds& x, const VertexIds& y) const { if (fabs (x.v.x - y.v.x) <= tolerance) { if (fabs (x.v.y - y.v.y) <= tolerance) { if (fabs (x.v.z - y.v.z) <= tolerance) { return true; } } } return false; } private: double tolerance; }; struct SketcherValidation::ConstraintIds { Base::Vector3d v; int First; int Second; Sketcher::PointPos FirstPos; Sketcher::PointPos SecondPos; }; struct SketcherValidation::Constraint_Less : public std::binary_function { bool operator()(const ConstraintIds& x, const ConstraintIds& y) const { int x1 = x.First; int x2 = x.Second; int y1 = y.First; int y2 = y.Second; if (x1 > x2) { std::swap(x1, x2); } if (y1 > y2) { std::swap(y1, y2); } if (x1 < y1) return true; else if (x1 > y1) return false; else if (x2 < y2) return true; else if (x2 > y2) return false; return false; } }; void SketcherValidation::on_findButton_clicked() { std::vector vertexIds; const std::vector& geom = sketch->getInternalGeometry(); for (std::size_t i=0; igetTypeId() == Part::GeomLineSegment::getClassTypeId()) { const Part::GeomLineSegment *segm = dynamic_cast(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(); vertexIds.push_back(id); } else if (g->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *segm = dynamic_cast(g); VertexIds id; id.GeoId = (int)i; id.PosId = Sketcher::start; id.v = segm->getStartPoint(); vertexIds.push_back(id); id.GeoId = (int)i; id.PosId = Sketcher::end; id.v = segm->getEndPoint(); vertexIds.push_back(id); } } std::set coincidences; double prec = Precision::Confusion(); QVariant v = ui->comboBoxTolerance->itemData(ui->comboBoxTolerance->currentIndex()); if (v.isValid()) prec = v.toDouble(); else prec = QLocale::system().toDouble(ui->comboBoxTolerance->currentText()); std::sort(vertexIds.begin(), vertexIds.end(), Vertex_Less(prec)); std::vector::iterator vt = vertexIds.begin(); Vertex_EqualTo pred(prec); while (vt < vertexIds.end()) { // get first item whose adjacent element has the same vertex coordinates vt = std::adjacent_find(vt, vertexIds.end(), pred); if (vt < vertexIds.end()) { std::vector::iterator vn; for (vn = vt+1; vn != vertexIds.end(); ++vn) { if (pred(*vt,*vn)) { ConstraintIds id; id.v = vt->v; id.First = vt->GeoId; id.FirstPos = vt->PosId; id.Second = vn->GeoId; id.SecondPos = vn->PosId; coincidences.insert(id); } else { break; } } vt = vn; } } std::vector constraint = sketch->Constraints.getValues(); for (std::vector::iterator it = constraint.begin(); it != constraint.end(); ++it) { if ((*it)->Type == Sketcher::Coincident) { ConstraintIds id; id.First = (*it)->First; id.FirstPos = (*it)->FirstPos; id.Second = (*it)->Second; id.SecondPos = (*it)->SecondPos; std::set::iterator pos = coincidences.find(id); if (pos != coincidences.end()) { coincidences.erase(pos); } } } this->vertexConstraints.clear(); this->vertexConstraints.reserve(coincidences.size()); std::vector points; points.reserve(coincidences.size()); for (std::set::iterator it = coincidences.begin(); it != coincidences.end(); ++it) { this->vertexConstraints.push_back(*it); points.push_back(it->v); } hidePoints(); if (this->vertexConstraints.empty()) { QMessageBox::information(this, tr("No missing coincidences"), tr("No missing coincidences found")); ui->fixButton->setEnabled(false); } else { showPoints(points); QMessageBox::warning(this, tr("Missing coincidences"), tr("%1 missing coincidences found").arg(this->vertexConstraints.size())); ui->fixButton->setEnabled(true); } } void SketcherValidation::on_fixButton_clicked() { // undo command open App::Document* doc = sketch->getDocument(); doc->openTransaction("add coincident constraint"); std::vector constr; for (std::vector::iterator it = this->vertexConstraints.begin(); it != this->vertexConstraints.end(); ++it) { Sketcher::Constraint* c = new Sketcher::Constraint(); c->Type = Sketcher::Coincident; c->First = it->First; c->Second = it->Second; c->FirstPos = it->FirstPos; c->SecondPos = it->SecondPos; constr.push_back(c); } sketch->addConstraints(constr); this->vertexConstraints.clear(); ui->fixButton->setEnabled(false); hidePoints(); for (std::vector::iterator it = constr.begin(); it != constr.end(); ++it) { delete *it; } // finish the transaction and update Gui::WaitCursor wc; doc->commitTransaction(); doc->recompute(); } void SketcherValidation::showPoints(const std::vector& pts) { SoCoordinate3 * coords = new SoCoordinate3(); SoDrawStyle * drawStyle = new SoDrawStyle(); drawStyle->pointSize = 6; SoPointSet* pcPoints = new SoPointSet(); coincidenceRoot = new SoGroup(); coincidenceRoot->addChild(drawStyle); SoSeparator* pointsep = new SoSeparator(); SoBaseColor * basecol = new SoBaseColor(); basecol->rgb.setValue(1.0f, 0.5f, 0.0f); pointsep->addChild(basecol); pointsep->addChild(coords); pointsep->addChild(pcPoints); coincidenceRoot->addChild(pointsep); // Draw markers SoBaseColor * markcol = new SoBaseColor(); markcol->rgb.setValue(1.0f, 1.0f, 0.0f); SoMarkerSet* marker = new SoMarkerSet(); marker->markerIndex=SoMarkerSet::PLUS_9_9; pointsep->addChild(markcol); pointsep->addChild(marker); int pts_size = (int)pts.size(); coords->point.setNum(pts_size); SbVec3f* c = coords->point.startEditing(); for (int i = 0; i < pts_size; i++) { const Base::Vector3d& v = pts[i]; c[i].setValue((float)v.x,(float)v.y,(float)v.z); } coords->point.finishEditing(); Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch); vp->getRoot()->addChild(coincidenceRoot); } void SketcherValidation::hidePoints() { if (coincidenceRoot) { Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sketch); vp->getRoot()->removeChild(coincidenceRoot); coincidenceRoot = 0; } } // ----------------------------------------------- TaskSketcherValidation::TaskSketcherValidation(Sketcher::SketchObject* Obj) { QWidget* widget = new SketcherValidation(Obj); Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( QPixmap(), widget->windowTitle(), true, 0); taskbox->groupLayout()->addWidget(widget); Content.push_back(taskbox); } TaskSketcherValidation::~TaskSketcherValidation() { } #include "moc_TaskSketcherValidation.cpp"