ViewProviderSketch.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2009 Jürgen Riegel <juergen.riegel@web.de>              *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 
00026 #ifndef _PreComp_
00027 # include <Standard_math.hxx>
00028 # include <Poly_Polygon3D.hxx>
00029 # include <Geom_BSplineCurve.hxx>
00030 # include <Geom_Circle.hxx>
00031 # include <Geom_TrimmedCurve.hxx>
00032 # include <Inventor/actions/SoGetBoundingBoxAction.h>
00033 # include <Inventor/SoPath.h>
00034 # include <Inventor/SbBox3f.h>
00035 # include <Inventor/SoPickedPoint.h>
00036 # include <Inventor/details/SoLineDetail.h>
00037 # include <Inventor/details/SoPointDetail.h>
00038 # include <Inventor/nodes/SoBaseColor.h>
00039 # include <Inventor/nodes/SoCoordinate3.h>
00040 # include <Inventor/nodes/SoDrawStyle.h>
00041 # include <Inventor/nodes/SoImage.h>
00042 # include <Inventor/nodes/SoLineSet.h>
00043 # include <Inventor/nodes/SoPointSet.h>
00044 # include <Inventor/nodes/SoMarkerSet.h>
00045 # include <Inventor/nodes/SoMaterial.h>
00046 # include <Inventor/nodes/SoAsciiText.h>
00047 # include <Inventor/nodes/SoTransform.h>
00048 # include <Inventor/nodes/SoSeparator.h>
00049 # include <Inventor/nodes/SoVertexProperty.h>
00050 # include <Inventor/nodes/SoTranslation.h>
00051 # include <Inventor/nodes/SoText2.h>
00052 # include <Inventor/nodes/SoFont.h>
00053 # include <Inventor/sensors/SoIdleSensor.h>
00054 # include <Inventor/nodes/SoCamera.h>
00055 
00057 # include <QAction>
00058 # include <QApplication>
00059 # include <QColor>
00060 # include <QDialog>
00061 # include <QFont>
00062 # include <QImage>
00063 # include <QMenu>
00064 # include <QMessageBox>
00065 # include <QPainter>
00066 #endif
00067 
00068 #include <Inventor/SbTime.h>
00069 
00071 #include <Base/Tools.h>
00072 #include <Base/Parameter.h>
00073 #include <Base/Console.h>
00074 #include <Base/Vector3D.h>
00075 #include <Gui/Application.h>
00076 #include <Gui/BitmapFactory.h>
00077 #include <Gui/Document.h>
00078 #include <Gui/Command.h>
00079 #include <Gui/Control.h>
00080 #include <Gui/Selection.h>
00081 #include <Gui/MainWindow.h>
00082 #include <Gui/MenuManager.h>
00083 #include <Gui/View3DInventor.h>
00084 #include <Gui/View3DInventorViewer.h>
00085 #include <Gui/DlgEditFileIncludeProptertyExternal.h>
00086 #include <Gui/SoFCUnifiedSelection.h>
00087 
00088 #include <Mod/Part/App/Geometry.h>
00089 #include <Mod/Sketcher/App/SketchObject.h>
00090 #include <Mod/Sketcher/App/Sketch.h>
00091 
00092 #include "SoZoomTranslation.h"
00093 #include "SoDatumLabel.h"
00094 #include "EditDatumDialog.h"
00095 #include "ViewProviderSketch.h"
00096 #include "DrawSketchHandler.h"
00097 #include "TaskDlgEditSketch.h"
00098 
00099 using namespace SketcherGui;
00100 using namespace Sketcher;
00101 
00102 SbColor ViewProviderSketch::VertexColor           (1.0f,0.149f,0.0f);   // #FF2600 -> (255, 38,  0)
00103 SbColor ViewProviderSketch::CurveColor            (1.0f,1.0f,1.0f);     // #FFFFFF -> (255,255,255)
00104 SbColor ViewProviderSketch::CurveDraftColor       (0.0f,0.0f,0.86f);    // #0000DC -> (  0,  0,220)
00105 SbColor ViewProviderSketch::CrossColorV           (0.8f,0.4f,0.4f);     // #CC6666 -> (204,102,102)
00106 SbColor ViewProviderSketch::CrossColorH           (0.4f,0.8f,0.4f);     // #66CC66 -> (102,204,102)
00107 SbColor ViewProviderSketch::FullyConstrainedColor (0.0f,1.0f,0.0f);     // #00FF00 -> (  0,255,  0)
00108 SbColor ViewProviderSketch::ConstrDimColor        (1.0f,0.149f,0.0f);   // #FF2600 -> (255, 38,  0)
00109 SbColor ViewProviderSketch::ConstrIcoColor        (1.0f,0.149f,0.0f);   // #FF2600 -> (255, 38,  0)
00110 SbColor ViewProviderSketch::PreselectColor        (0.88f,0.88f,0.0f);   // #E1E100 -> (225,225,  0)
00111 SbColor ViewProviderSketch::SelectColor           (0.11f,0.68f,0.11f);  // #1CAD1C -> ( 28,173, 28)
00112 
00113 // Variables for holding previous click
00114 SbTime  ViewProviderSketch::prvClickTime;
00115 SbVec3f ViewProviderSketch::prvClickPoint;
00116 
00117 //**************************************************************************
00118 // Edit data structure
00119 
00121 struct EditData {
00122     EditData():
00123     sketchHandler(0),
00124     DragPoint(-1),
00125     DragCurve(-1),
00126     DragConstraint(-1),
00127     PreselectPoint(-1),
00128     PreselectCurve(-1),
00129     PreselectCross(-1),
00130     PreselectConstraint(-1),
00131     blockedPreselection(false),
00132     FullyConstrained(false),
00133     //ActSketch(0),
00134     EditRoot(0),
00135     PointsMaterials(0),
00136     CurvesMaterials(0),
00137     PointsCoordinate(0),
00138     CurvesCoordinate(0),
00139     CurveSet(0),
00140     PointSet(0)
00141     {}
00142 
00143     // pointer to the active handler for new sketch objects
00144     DrawSketchHandler *sketchHandler;
00145 
00146     // dragged point
00147     int DragPoint;
00148     // dragged curve
00149     int DragCurve;
00150     // dragged constraint
00151     int DragConstraint;
00152 
00153     SbColor PreselectOldColor;
00154     int PreselectPoint;
00155     int PreselectCurve;
00156     int PreselectCross;
00157     int PreselectConstraint;
00158     bool blockedPreselection;
00159     bool FullyConstrained;
00160 
00161     // pointer to the Solver
00162     Sketcher::Sketch ActSketch;
00163     // container to track our own selected parts
00164     std::set<int> SelPointSet;
00165     std::set<int> SelCurvSet;
00166     std::set<int> SelConstraintSet;
00167     std::set<int> SelCrossSet;
00168 
00169     // helper data structure for the constraint rendering
00170     std::vector<ConstraintType> vConstrType;
00171 
00172     // nodes for the visuals
00173     SoSeparator   *EditRoot;
00174     SoMaterial    *PointsMaterials;
00175     SoMaterial    *CurvesMaterials;
00176     SoMaterial    *RootCrossMaterialsV;
00177     SoMaterial    *RootCrossMaterialsH;
00178     SoMaterial    *EditCurvesMaterials;
00179     SoCoordinate3 *PointsCoordinate;
00180     SoCoordinate3 *CurvesCoordinate;
00181     SoCoordinate3 *RootCrossCoordinateV;
00182     SoCoordinate3 *RootCrossCoordinateH;
00183     SoCoordinate3 *EditCurvesCoordinate;
00184     SoLineSet     *CurveSet;
00185     SoLineSet     *EditCurveSet;
00186     SoLineSet     *RootCrossSetV;
00187     SoLineSet     *RootCrossSetH;
00188     SoMarkerSet   *PointSet;
00189 
00190     SoText2       *textX;
00191     SoTranslation *textPos;
00192 
00193     SoGroup       *constrGroup;
00194 };
00195 
00196 
00197 //**************************************************************************
00198 // Construction/Destruction
00199 
00200 PROPERTY_SOURCE(SketcherGui::ViewProviderSketch, PartGui::ViewProvider2DObject)
00201 
00202 
00203 ViewProviderSketch::ViewProviderSketch()
00204   : edit(0),
00205     Mode(STATUS_NONE)
00206 {
00207     // FIXME Should this be placed in here?
00208     ADD_PROPERTY_TYPE(Autoconstraints,(true),"Auto Constraints",(App::PropertyType)(App::Prop_None),"Create auto constraints");
00209 
00210     sPixmap = "Sketcher_Sketch";
00211     LineColor.setValue(1,1,1);
00212     PointColor.setValue(1,1,1);
00213     PointSize.setValue(4);
00214 
00215     zCross=0.001f;
00216     zConstr=0.002f;
00217     zLines=0.003f;
00218     zPoints=0.004f;
00219     zHighlight=0.005f;
00220     zText=0.006f;
00221     zEdit=0.001f;
00222 
00223     xInit=0;
00224     yInit=0;
00225     relative=false;
00226 }
00227 
00228 ViewProviderSketch::~ViewProviderSketch()
00229 {
00230 }
00231 
00232 // handler management ***************************************************************
00233 void ViewProviderSketch::activateHandler(DrawSketchHandler *newHandler)
00234 {
00235     assert(edit);
00236     assert(edit->sketchHandler == 0);
00237     edit->sketchHandler = newHandler;
00238     Mode = STATUS_SKETCH_UseHandler;
00239     edit->sketchHandler->sketchgui = this;
00240     edit->sketchHandler->activated(this);
00241 }
00242 
00244 void ViewProviderSketch::purgeHandler(void)
00245 {
00246     assert(edit);
00247     assert(edit->sketchHandler != 0);
00248     delete(edit->sketchHandler);
00249     edit->sketchHandler = 0;
00250     Mode = STATUS_NONE;
00251 }
00252 
00253 // **********************************************************************************
00254 
00255 bool ViewProviderSketch::keyPressed(bool pressed, int key)
00256 {
00257     switch (key)
00258     {
00259     case SoKeyboardEvent::ESCAPE:
00260         {
00261             // make the handler quit but not the edit mode
00262             if (edit && edit->sketchHandler) {
00263                 if (!pressed)
00264                     edit->sketchHandler->quit();
00265                 return true;
00266             }
00267             return false;
00268         }
00269     }
00270 
00271     return true; // handle all other key events
00272 }
00273 
00274 void ViewProviderSketch::snapToGrid(double &x, double &y)
00275 {
00276     if (GridSnap.getValue() != false) {
00277         // Snap Tolerance in pixels
00278         const double snapTol = GridSize.getValue() / 5;
00279 
00280         double tmpX = x, tmpY = y;
00281 
00282         // Find Nearest Snap points
00283         tmpX = tmpX / GridSize.getValue();
00284         tmpX = tmpX < 0.0 ? ceil(tmpX - 0.5) : floor(tmpX + 0.5);
00285         tmpX *= GridSize.getValue();
00286 
00287         tmpY = tmpY / GridSize.getValue();
00288         tmpY = tmpY < 0.0 ? ceil(tmpY - 0.5) : floor(tmpY + 0.5);
00289         tmpY *= GridSize.getValue();
00290 
00291         // Check if x within snap tolerance
00292         if (x < tmpX + snapTol && x > tmpX - snapTol)
00293             x = tmpX; // Snap X Mouse Position
00294 
00295          // Check if y within snap tolerance
00296         if (y < tmpY + snapTol && y > tmpY - snapTol)
00297             y = tmpY; // Snap Y Mouse Position
00298     }
00299 }
00300 
00301 void ViewProviderSketch::getCoordsOnSketchPlane(double &u, double &v,const SbVec3f &point, const SbVec3f &normal)
00302 {
00303     // Plane form
00304     Base::Vector3d R0(0,0,0),RN(0,0,1),RX(1,0,0),RY(0,1,0);
00305 
00306     // move to position of Sketch
00307     Base::Placement Plz = getSketchObject()->Placement.getValue();
00308     R0 = Plz.getPosition() ;
00309     Base::Rotation tmp(Plz.getRotation());
00310     tmp.multVec(RN,RN);
00311     tmp.multVec(RX,RX);
00312     tmp.multVec(RY,RY);
00313     Plz.setRotation(tmp);
00314 
00315     // line
00316     Base::Vector3d R1(point[0],point[1],point[2]),RA(normal[0],normal[1],normal[2]);
00317     if (fabs(RN*RA) < FLT_EPSILON)
00318         throw Base::Exception("View direction is parallel to sketch plane");
00319     // intersection point on plane
00320     Base::Vector3d S = R1 + ((RN * (R0-R1))/(RN*RA))*RA;
00321 
00322     // distance to x Axle of the sketch
00323     S.TransformToCoordinateSystem(R0,RX,RY);
00324 
00325     u = S.x;
00326     v = S.y;
00327 }
00328 
00329 bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVec3f &point,
00330                                             const SbVec3f &normal, const SoPickedPoint *pp)
00331 {
00332     assert(edit);
00333 
00334     // Radius maximum to allow double click event
00335     const int dblClickRadius = 5;
00336 
00337     double x,y;
00338     SbVec3f pos = point;
00339     if (pp) {
00340         const SoDetail *detail = pp->getDetail();
00341         if (detail && detail->getTypeId() == SoPointDetail::getClassTypeId()) {
00342             pos = pp->getPoint();
00343         }
00344     }
00345 
00346     getCoordsOnSketchPlane(x,y,pos,normal);
00347     snapToGrid(x, y);
00348 
00349     // Left Mouse button ****************************************************
00350     if (Button == 1) {
00351         if (pressed) {
00352             // Do things depending on the mode of the user interaction
00353             switch (Mode) {
00354                 case STATUS_NONE:{
00355                     bool done=false;
00356                     // Double click events variables
00357                     SbTime tmp = (SbTime::getTimeOfDay() - prvClickTime);
00358                     float dci = (float) QApplication::doubleClickInterval()/1000.0f;
00359                     float length = (point - prvClickPoint).length();
00360 
00361                     if (edit->PreselectPoint >=0) {
00362                         //Base::Console().Log("start dragging, point:%d\n",this->DragPoint);
00363                         Mode = STATUS_SELECT_Point;
00364                         done = true;
00365                     } else if (edit->PreselectCurve >=0) {
00366                         //Base::Console().Log("start dragging, point:%d\n",this->DragPoint);
00367                         Mode = STATUS_SELECT_Edge;
00368                         done = true;
00369                     } else if (edit->PreselectCross >=0) {
00370                         //Base::Console().Log("start dragging, point:%d\n",this->DragPoint);
00371                         Mode = STATUS_SELECT_Cross;
00372                         done = true;
00373                     } else if (edit->PreselectConstraint >=0) {
00374                         //Base::Console().Log("start dragging, point:%d\n",this->DragPoint);
00375                         Mode = STATUS_SELECT_Constraint;
00376                         done = true;
00377 
00378                     }
00379 
00380                     if (done && length <  dblClickRadius && tmp.getValue() < dci) {
00381                         // Double Click Event Occured
00382                         editDoubleClicked();
00383                         // Reset Double Click Static Variables
00384                         prvClickTime = SbTime();
00385                         prvClickPoint = SbVec3f(0.0f, 0.0f, 0.0f);
00386                         Mode = STATUS_NONE;
00387 
00388                     } else {
00389                         prvClickTime = SbTime::getTimeOfDay();
00390                         prvClickPoint = point;
00391                     }
00392 
00393                     return done;
00394                 }
00395                 case STATUS_SKETCH_UseHandler:
00396                     return edit->sketchHandler->pressButton(Base::Vector2D(x,y));
00397                 default:
00398                     return false;
00399             }
00400         }
00401         else {
00402             // Do things depending on the mode of the user interaction
00403             switch (Mode) {
00404                 case STATUS_SELECT_Point:
00405                     if (pp) {
00406                         //Base::Console().Log("Select Point:%d\n",this->DragPoint);
00407                         // Do selection
00408                         std::stringstream ss;
00409                         ss << "Vertex" << edit->PreselectPoint;
00410 
00411                         if (Gui::Selection().isSelected(getSketchObject()->getDocument()->getName()
00412                            ,getSketchObject()->getNameInDocument(),ss.str().c_str()) ) {
00413                              Gui::Selection().rmvSelection(getSketchObject()->getDocument()->getName()
00414                                                           ,getSketchObject()->getNameInDocument(), ss.str().c_str());
00415                         } else {
00416                             Gui::Selection().addSelection(getSketchObject()->getDocument()->getName()
00417                                                          ,getSketchObject()->getNameInDocument()
00418                                                          ,ss.str().c_str()
00419                                                          ,pp->getPoint()[0]
00420                                                          ,pp->getPoint()[1]
00421                                                          ,pp->getPoint()[2]);
00422                             this->edit->DragPoint = -1;
00423                             this->edit->DragCurve = -1;
00424                             this->edit->DragConstraint = -1;
00425                         }
00426                     }
00427                     Mode = STATUS_NONE;
00428                     return true;
00429                 case STATUS_SELECT_Edge:
00430                     if (pp) {
00431                         //Base::Console().Log("Select Point:%d\n",this->DragPoint);
00432                         std::stringstream ss;
00433                         ss << "Edge" << edit->PreselectCurve;
00434 
00435                         // If edge already selected move from selection
00436                         if (Gui::Selection().isSelected(getSketchObject()->getDocument()->getName()
00437                                                        ,getSketchObject()->getNameInDocument(),ss.str().c_str()) ) {
00438                             Gui::Selection().rmvSelection(getSketchObject()->getDocument()->getName()
00439                                                          ,getSketchObject()->getNameInDocument(), ss.str().c_str());
00440                         } else {
00441                             // Add edge to the selection
00442                             Gui::Selection().addSelection(getSketchObject()->getDocument()->getName()
00443                                                          ,getSketchObject()->getNameInDocument()
00444                                                          ,ss.str().c_str()
00445                                                          ,pp->getPoint()[0]
00446                                                          ,pp->getPoint()[1]
00447                                                          ,pp->getPoint()[2]);
00448                             this->edit->DragPoint = -1;
00449                             this->edit->DragCurve = -1;
00450                             this->edit->DragConstraint = -1;
00451                         }
00452                     }
00453                     Mode = STATUS_NONE;
00454                     return true;
00455                 case STATUS_SELECT_Cross:
00456                     if (pp) {
00457                         //Base::Console().Log("Select Point:%d\n",this->DragPoint);
00458                         std::stringstream ss;
00459                         switch(edit->PreselectCross){
00460                             case 0: ss << "RootPoint" ; break;
00461                             case 1: ss << "H_Axis"    ; break;
00462                             case 2: ss << "V_Axis"    ; break;
00463                         }
00464 
00465 
00466                         // If cross already selected move from selection
00467                         if (Gui::Selection().isSelected(getSketchObject()->getDocument()->getName()
00468                                                        ,getSketchObject()->getNameInDocument(),ss.str().c_str()) ) {
00469                             Gui::Selection().rmvSelection(getSketchObject()->getDocument()->getName()
00470                                                          ,getSketchObject()->getNameInDocument(), ss.str().c_str());
00471                         } else {
00472                             // Add cross to the selection
00473                             Gui::Selection().addSelection(getSketchObject()->getDocument()->getName()
00474                                                          ,getSketchObject()->getNameInDocument()
00475                                                          ,ss.str().c_str()
00476                                                          ,pp->getPoint()[0]
00477                                                          ,pp->getPoint()[1]
00478                                                          ,pp->getPoint()[2]);
00479                             this->edit->DragPoint = -1;
00480                             this->edit->DragCurve = -1;
00481                             this->edit->DragConstraint = -1;
00482                         }
00483                     }
00484                     Mode = STATUS_NONE;
00485                     return true;
00486                 case STATUS_SELECT_Constraint:
00487                     if (pp) {
00488 
00489                         std::stringstream ss;
00490                         ss << "Constraint" << edit->PreselectConstraint;
00491 
00492                         // If the constraint already selected remove
00493                         if (Gui::Selection().isSelected(getSketchObject()->getDocument()->getName()
00494                                                        ,getSketchObject()->getNameInDocument(),ss.str().c_str()) ) {
00495                             Gui::Selection().rmvSelection(getSketchObject()->getDocument()->getName()
00496                                                          ,getSketchObject()->getNameInDocument(), ss.str().c_str());
00497                         } else {
00498                             // Add constraint to current selection
00499                             Gui::Selection().addSelection(getSketchObject()->getDocument()->getName()
00500                                                          ,getSketchObject()->getNameInDocument()
00501                                                          ,ss.str().c_str()
00502                                                          ,pp->getPoint()[0]
00503                                                          ,pp->getPoint()[1]
00504                                                          ,pp->getPoint()[2]);
00505                             this->edit->DragPoint = -1;
00506                             this->edit->DragCurve = -1;
00507                             this->edit->DragConstraint = -1;
00508                         }
00509                     }
00510                     Mode = STATUS_NONE;
00511                     return true;
00512                 case STATUS_SKETCH_DragPoint:
00513                     if (edit->DragPoint != -1 && pp) {
00514                         int GeoId;
00515                         Sketcher::PointPos PosId;
00516                         getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId);
00517                         Gui::Command::openCommand("Drag Point");
00518                         Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.movePoint(%i,%i,App.Vector(%f,%f,0),%i)"
00519                                                ,getObject()->getNameInDocument()
00520                                                ,GeoId, PosId, x-xInit, y-yInit, relative ? 1 : 0
00521                                                );
00522                         Gui::Command::commitCommand();
00523                         Gui::Command::updateActive();
00524 
00525                         setPreselectPoint(edit->DragPoint);
00526                         edit->DragPoint = -1;
00527                         //updateColor();
00528                     }
00529                     resetPositionText();
00530                     Mode = STATUS_NONE;
00531                     return true;
00532                 case STATUS_SKETCH_DragCurve:
00533                     if (edit->DragCurve != -1 && pp) {
00534                         const std::vector<Part::Geometry *> *geomlist;
00535                         geomlist = &getSketchObject()->Geometry.getValues();
00536                         Part::Geometry *geo = (*geomlist)[edit->DragCurve];
00537                         if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId() ||
00538                             geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ||
00539                             geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
00540                             Gui::Command::openCommand("Drag Curve");
00541                             Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.movePoint(%i,%i,App.Vector(%f,%f,0),%i)"
00542                                                    ,getObject()->getNameInDocument()
00543                                                    ,edit->DragCurve, Sketcher::none, x-xInit, y-yInit, relative ? 1 : 0
00544                                                    );
00545                             Gui::Command::commitCommand();
00546                             Gui::Command::updateActive();
00547                         }
00548                         edit->PreselectCurve = edit->DragCurve;
00549                         edit->DragCurve = -1;
00550                         //updateColor();
00551                     }
00552                     resetPositionText();
00553                     Mode = STATUS_NONE;
00554                     return true;
00555                 case STATUS_SKETCH_DragConstraint:
00556                     if (edit->DragConstraint != -1 && pp) {
00557                         Gui::Command::openCommand("Drag Constraint");
00558                         moveConstraint(edit->DragConstraint, Base::Vector2D(x, y));
00559                         edit->PreselectConstraint = edit->DragConstraint;
00560                         edit->DragConstraint = -1;
00561                         //updateColor();
00562                     }
00563                     Mode = STATUS_NONE;
00564                     return true;
00565                 case STATUS_SKETCH_UseHandler:
00566                     return edit->sketchHandler->releaseButton(Base::Vector2D(x,y));
00567                 case STATUS_NONE:
00568                 default:
00569                     return false;
00570             }
00571         }
00572     }
00573     // Right mouse button ****************************************************
00574     else if (Button == 2) {
00575         if (!pressed) {
00576             switch (Mode) {
00577                 case STATUS_SKETCH_UseHandler:
00578                     // make the handler quit
00579                     edit->sketchHandler->quit();
00580                     return true;
00581                 case STATUS_NONE:
00582                     {
00583                         // A right click shouldn't change the Edit Mode
00584                         if (edit->PreselectPoint >=0) {
00585                             return true;
00586                         } else if (edit->PreselectCurve >=0) {
00587                             return true;
00588                         } else if (edit->PreselectConstraint >=0) {
00589                             return true;
00590                         } else {
00591                             //Get Viewer
00592                             Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView();
00593                             Gui::View3DInventorViewer *viewer ;
00594                             viewer = static_cast<Gui::View3DInventor *>(mdi)->getViewer();
00595 
00596                             Gui::MenuItem *geom = new Gui::MenuItem();
00597                             geom->setCommand("Sketcher geoms");
00598                             *geom /*<< "Sketcher_CreatePoint"*/
00599                                 << "Sketcher_CreateArc"
00600                                 << "Sketcher_CreateCircle"
00601                                 << "Sketcher_CreateLine"
00602                                 << "Sketcher_CreatePolyline"
00603                                 << "Sketcher_CreateRectangle"
00604                                 << "Sketcher_CreateFillet"
00605                                 << "Sketcher_Trimming"
00606                                 << "Sketcher_ToggleConstruction"
00607                                 /*<< "Sketcher_CreateText"*/
00608                                 /*<< "Sketcher_CreateDraftLine"*/;
00609 
00610                             Gui::Application::Instance->setupContextMenu("View", geom);
00611                             //Create the Context Menu using the Main View Qt Widget
00612                             QMenu contextMenu(viewer->getGLWidget());
00613                             Gui::MenuManager::getInstance()->setupContextMenu(geom, contextMenu);
00614                             QAction *used = contextMenu.exec(QCursor::pos());
00615 
00616                             return true;
00617                         }
00618                     }
00619                 case STATUS_SELECT_Point:
00620                     break;
00621                 case STATUS_SELECT_Edge:
00622                     {
00623                         //Get Viewer
00624                         Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView();
00625                         Gui::View3DInventorViewer *viewer ;
00626                         viewer = static_cast<Gui::View3DInventor *>(mdi)->getViewer();
00627 
00628                         Gui::MenuItem *geom = new Gui::MenuItem();
00629                         geom->setCommand("Sketcher constraints");
00630                         *geom << "Sketcher_ConstrainVertical"
00631                         << "Sketcher_ConstrainHorizontal";
00632 
00633                         // Gets a selection vector
00634                         std::vector<Gui::SelectionObject> selection = Gui::Selection().getSelectionEx();
00635 
00636                         bool rightClickOnSelectedLine = false;
00637 
00638                         /*
00639                          * Add Multiple Line Constraints to the menu
00640                          */
00641                         // only one sketch with its subelements are allowed to be selected
00642                         if (selection.size() == 1) {
00643                             // get the needed lists and objects
00644                             const std::vector<std::string> &SubNames = selection[0].getSubNames();
00645 
00646                             // Two Objects are selected
00647                             if (SubNames.size() == 2) {
00648                                 // go through the selected subelements
00649                                 for (std::vector<std::string>::const_iterator it=SubNames.begin();
00650                                      it!=SubNames.end();++it) {
00651 
00652                                     // If the object selected is of type edge
00653                                     if (it->size() > 4 && it->substr(0,4) == "Edge") {
00654                                         // Get the index of the object selected
00655                                         int index=std::atoi(it->substr(4,4000).c_str());
00656                                         if (edit->PreselectCurve == index)
00657                                             rightClickOnSelectedLine = true;
00658                                     } else {
00659                                         // The selection is not exclusivly edges
00660                                         rightClickOnSelectedLine = false;
00661                                     }
00662                                 } // End of Iteration
00663                             }
00664                         }
00665 
00666                         if (rightClickOnSelectedLine) {
00667                             *geom << "Sketcher_ConstrainParallel"
00668                                   << "Sketcher_ConstrainPerpendicular";
00669                         }
00670 
00671                         Gui::Application::Instance->setupContextMenu("View", geom);
00672                         //Create the Context Menu using the Main View Qt Widget
00673                         QMenu contextMenu(viewer->getGLWidget());
00674                         Gui::MenuManager::getInstance()->setupContextMenu(geom, contextMenu);
00675                         QAction *used = contextMenu.exec(QCursor::pos());
00676 
00677                         return true;
00678                     }
00679                 case STATUS_SELECT_Cross:
00680                 case STATUS_SELECT_Constraint:
00681                 case STATUS_SKETCH_DragPoint:
00682                 case STATUS_SKETCH_DragCurve:
00683                 case STATUS_SKETCH_DragConstraint:
00684                 break;
00685             }
00686         }
00687     }
00688 
00689     return false;
00690 }
00691 
00692 void ViewProviderSketch::editDoubleClicked(void)
00693 {
00694     if (edit->PreselectPoint >=0) {
00695          Base::Console().Log("double click point:%d\n",edit->PreselectPoint);
00696      } else if (edit->PreselectCurve >=0) {
00697          Base::Console().Log("double click edge:%d\n",edit->PreselectCurve);
00698      } else if (edit->PreselectCross >=0) {
00699          Base::Console().Log("double click cross:%d\n",edit->PreselectCross);
00700      } else if (edit->PreselectConstraint >=0) {
00701         // Find the constraint
00702         Base::Console().Log("double click constraint:%d\n",edit->PreselectConstraint);
00703 
00704         const std::vector<Sketcher::Constraint *> &ConStr = getSketchObject()->Constraints.getValues();
00705         Constraint *Constr = ConStr[edit->PreselectConstraint];
00706 
00707         // if its the right constraint
00708         if (Constr->Type == Sketcher::Distance ||
00709             Constr->Type == Sketcher::DistanceX || Constr->Type == Sketcher::DistanceY ||
00710             Constr->Type == Sketcher::Radius || Constr->Type == Sketcher::Angle) {
00711 
00712             EditDatumDialog * editDatumDialog = new EditDatumDialog(this, edit->PreselectConstraint);
00713             SoIdleSensor* sensor = new SoIdleSensor(EditDatumDialog::run, editDatumDialog);
00714             sensor->schedule();
00715         }
00716     }
00717 }
00718 
00719 bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal, const SoPickedPoint *pp)
00720 {
00721     if (!edit)
00722         return false;
00723     assert(edit);
00724 
00725     double x,y;
00726     getCoordsOnSketchPlane(x,y,point,normal);
00727     snapToGrid(x, y);
00728 
00729     bool preselectChanged;
00730     if (Mode!=STATUS_SKETCH_DragPoint && Mode!=STATUS_SKETCH_DragCurve &&
00731         Mode!=STATUS_SKETCH_DragConstraint) {
00732         int PtIndex,CurvIndex,ConstrIndex,CrossIndex;
00733         preselectChanged = detectPreselection(pp,PtIndex,CurvIndex,ConstrIndex,CrossIndex);
00734     }
00735 
00736     switch (Mode) {
00737         case STATUS_NONE:
00738             if (preselectChanged) {
00739                 this->drawConstraintIcons();
00740                 this->updateColor();
00741                 return true;
00742             }
00743             return false;
00744         case STATUS_SELECT_Point:
00745             if (!edit->ActSketch.hasConflicts() &&
00746                 edit->PreselectPoint != -1 && edit->DragPoint != edit->PreselectPoint) {
00747                 Mode = STATUS_SKETCH_DragPoint;
00748                 edit->DragPoint = edit->PreselectPoint;
00749                 int GeoId;
00750                 Sketcher::PointPos PosId;
00751                 getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId);
00752                 edit->ActSketch.initMove(GeoId, PosId);
00753                 relative = false;
00754                 xInit = 0;
00755                 yInit = 0;
00756             } else {
00757                 Mode = STATUS_NONE;
00758             }
00759             resetPreselectPoint();
00760             edit->PreselectCurve = -1;
00761             edit->PreselectCross = -1;
00762             edit->PreselectConstraint = -1;
00763             return true;
00764         case STATUS_SELECT_Edge:
00765             if (!edit->ActSketch.hasConflicts() &&
00766                 edit->PreselectCurve != -1 && edit->DragCurve != edit->PreselectCurve) {
00767                 Mode = STATUS_SKETCH_DragCurve;
00768                 edit->DragCurve = edit->PreselectCurve;
00769                 edit->ActSketch.initMove(edit->DragCurve, Sketcher::none);
00770                 Part::Geometry *geo = getSketchObject()->Geometry.getValues()[edit->DragCurve];
00771                 if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
00772                     relative = true;
00773                     xInit = x;
00774                     yInit = y;
00775                 } else {
00776                     relative = false;
00777                     xInit = 0;
00778                     yInit = 0;
00779                 }
00780             } else {
00781                 Mode = STATUS_NONE;
00782             }
00783             resetPreselectPoint();
00784             edit->PreselectCurve = -1;
00785             edit->PreselectCross = -1;
00786             edit->PreselectConstraint = -1;
00787             return true;
00788         case STATUS_SELECT_Constraint:
00789             Mode = STATUS_SKETCH_DragConstraint;
00790             edit->DragConstraint = edit->PreselectConstraint;
00791             resetPreselectPoint();
00792             edit->PreselectCurve = -1;
00793             edit->PreselectCross = -1;
00794             edit->PreselectConstraint = -1;
00795             return true;
00796         case STATUS_SKETCH_DragPoint:
00797             if (edit->DragPoint != -1) {
00798                 //Base::Console().Log("Drag Point:%d\n",edit->DragPoint);
00799                 int GeoId;
00800                 Sketcher::PointPos PosId;
00801                 getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId);
00802                 Base::Vector3d vec(x-xInit,y-yInit,0);
00803                 if (edit->ActSketch.movePoint(GeoId, PosId, vec, relative) == 0) {
00804                     setPositionText(Base::Vector2D(x,y));
00805                     draw(true);
00806                     signalSolved(0, edit->ActSketch.SolveTime);
00807                 } else {
00808                     signalSolved(1, edit->ActSketch.SolveTime);
00809                     //Base::Console().Log("Error solving:%d\n",ret);
00810                 }
00811             }
00812             return true;
00813         case STATUS_SKETCH_DragCurve:
00814             if (edit->DragCurve != -1) {
00815                 Base::Vector3d vec(x-xInit,y-yInit,0);
00816                 if (edit->ActSketch.movePoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) {
00817                     setPositionText(Base::Vector2D(x,y));
00818                     draw(true);
00819                     signalSolved(0, edit->ActSketch.SolveTime);
00820                 } else {
00821                     signalSolved(1, edit->ActSketch.SolveTime);
00822                 }
00823             }
00824             return true;
00825         case STATUS_SKETCH_DragConstraint:
00826             if (edit->DragConstraint != -1) {
00827                 moveConstraint(edit->DragConstraint, Base::Vector2D(x,y));
00828             }
00829             return true;
00830         case STATUS_SKETCH_UseHandler:
00831             edit->sketchHandler->mouseMove(Base::Vector2D(x,y));
00832             if (preselectChanged) {
00833                 this->drawConstraintIcons();
00834                 this->updateColor();
00835             }
00836             return true;
00837         default:
00838             return false;
00839     }
00840 
00841     return false;
00842 }
00843 
00844 void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPos)
00845 {
00846     // are we in edit?
00847     if (!edit)
00848         return;
00849 
00850     const std::vector<Sketcher::Constraint *> &ConStr = getSketchObject()->Constraints.getValues();
00851     Constraint *Constr = ConStr[constNum];
00852 
00853     if (Constr->Type == Distance || Constr->Type == DistanceX || Constr->Type == DistanceY ||
00854         Constr->Type == Radius) {
00855 
00856         const std::vector<Part::Geometry *> geomlist = edit->ActSketch.getGeometry();
00857         assert(Constr->First < int(geomlist.size()));
00858 
00859         Base::Vector3d p1(0.,0.,0.), p2(0.,0.,0.);
00860         if (Constr->SecondPos != Sketcher::none) { // point to point distance
00861             p1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos);
00862             p2 = edit->ActSketch.getPoint(Constr->Second, Constr->SecondPos);
00863         } else if (Constr->Second != Constraint::GeoUndef) { // point to line distance
00864             p1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos);
00865             const Part::Geometry *geo = geomlist[Constr->Second];
00866             if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
00867                 const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geo);
00868                 Base::Vector3d l2p1 = lineSeg->getStartPoint();
00869                 Base::Vector3d l2p2 = lineSeg->getEndPoint();
00870                 // calculate the projection of p1 onto line2
00871                 p2.ProjToLine(p1-l2p1, l2p2-l2p1);
00872                 p2 += p1;
00873             } else
00874                 return;
00875         } else if (Constr->FirstPos != Sketcher::none) {
00876             p2 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos);
00877         } else if (Constr->First != Constraint::GeoUndef) {
00878             const Part::Geometry *geo = geomlist[Constr->First];
00879             if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
00880                 const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geo);
00881                 p1 = lineSeg->getStartPoint();
00882                 p2 = lineSeg->getEndPoint();
00883             } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
00884                 const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(geo);
00885                 double radius = arc->getRadius();
00886                 double startangle, endangle;
00887                 arc->getRange(startangle, endangle);
00888                 double angle = (startangle + endangle)/2;
00889                 p1 = arc->getCenter();
00890                 p2 = p1 + radius * Base::Vector3d(cos(angle),sin(angle),0.);
00891             }
00892             else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
00893                 const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo);
00894                 double radius = circle->getRadius();
00895                 double angle = M_PI/4;
00896                 p1 = circle->getCenter();
00897                 p2 = p1 + radius * Base::Vector3d(cos(angle),sin(angle),0.);
00898             } else
00899                 return;
00900         } else
00901             return;
00902 
00903         Base::Vector3d vec = Base::Vector3d(toPos.fX, toPos.fY, 0) - p2;
00904 
00905         Base::Vector3d dir;
00906         if (Constr->Type == Distance || Constr->Type == Radius)
00907             dir = (p2-p1).Normalize();
00908         else if (Constr->Type == DistanceX)
00909             dir = Base::Vector3d( (p2.x - p1.x >= FLT_EPSILON) ? 1 : -1, 0, 0);
00910         else if (Constr->Type == DistanceY)
00911             dir = Base::Vector3d(0, (p2.y - p1.y >= FLT_EPSILON) ? 1 : -1, 0);
00912 
00913         if (Constr->Type == Radius)
00914             Constr->LabelDistance = vec.x * dir.x + vec.y * dir.y;
00915         else {
00916             Base::Vector3d norm(-dir.y,dir.x,0);
00917             Constr->LabelDistance = vec.x * norm.x + vec.y * norm.y;
00918         }
00919     }
00920     else if (Constr->Type == Angle) {
00921         const std::vector<Part::Geometry *> geomlist = edit->ActSketch.getGeometry();
00922         assert(Constr->First < int(geomlist.size()));
00923 
00924         Base::Vector3d p0(0.,0.,0.);
00925         if (Constr->Second != Constraint::GeoUndef) { // line to line angle
00926             const Part::Geometry *geo1 = geomlist[Constr->First];
00927             const Part::Geometry *geo2 = geomlist[Constr->Second];
00928             if (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() ||
00929                 geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId())
00930                 return;
00931             const Part::GeomLineSegment *lineSeg1 = dynamic_cast<const Part::GeomLineSegment *>(geo1);
00932             const Part::GeomLineSegment *lineSeg2 = dynamic_cast<const Part::GeomLineSegment *>(geo2);
00933 
00934             bool flip1 = (Constr->FirstPos == end);
00935             bool flip2 = (Constr->SecondPos == end);
00936             Base::Vector3d dir1 = (flip1 ? -1. : 1.) * (lineSeg1->getEndPoint()-lineSeg1->getStartPoint());
00937             Base::Vector3d dir2 = (flip2 ? -1. : 1.) * (lineSeg2->getEndPoint()-lineSeg2->getStartPoint());
00938             Base::Vector3d pnt1 = flip1 ? lineSeg1->getEndPoint() : lineSeg1->getStartPoint();
00939             Base::Vector3d pnt2 = flip2 ? lineSeg2->getEndPoint() : lineSeg2->getStartPoint();
00940 
00941             // line-line intersection
00942             {
00943                 double det = dir1.x*dir2.y - dir1.y*dir2.x;
00944                 if ((det > 0 ? det : -det) < 1e-10)
00945                     return;
00946                 double c1 = dir1.y*pnt1.x - dir1.x*pnt1.y;
00947                 double c2 = dir2.y*pnt2.x - dir2.x*pnt2.y;
00948                 double x = (dir1.x*c2 - dir2.x*c1)/det;
00949                 double y = (dir1.y*c2 - dir2.y*c1)/det;
00950                 p0 = Base::Vector3d(x,y,0);
00951             }
00952         } else if (Constr->First != Constraint::GeoUndef) { // line angle
00953             const Part::Geometry *geo = geomlist[Constr->First];
00954             if (geo->getTypeId() != Part::GeomLineSegment::getClassTypeId())
00955                 return;
00956             const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geo);
00957             p0 = (lineSeg->getEndPoint()+lineSeg->getStartPoint())/2;
00958         } else
00959             return;
00960 
00961         Base::Vector3d vec = Base::Vector3d(toPos.fX, toPos.fY, 0) - p0;
00962         Constr->LabelDistance = vec.Length()/2;
00963     }
00964     draw(true);
00965 }
00966 
00967 bool ViewProviderSketch::isConstraintAtPosition(const Base::Vector3d &constrPos, const SoNode *constraint)
00968 {
00969     assert(edit);
00970     Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView();
00971     Gui::View3DInventorViewer *viewer = static_cast<Gui::View3DInventor *>(mdi)->getViewer();
00972 
00973     SoRayPickAction rp(viewer->getViewportRegion());
00974     rp.setRadius(0.1f);
00975 
00976     rp.setRay(SbVec3f(constrPos.x, constrPos.y,constrPos.z), SbVec3f(0, 0, 1) );
00977     //problem
00978     rp.apply(edit->constrGroup); // We could narrow it down to just the SoGroup containing the constraints
00979 
00980     // returns a copy of the point
00981     SoPickedPoint *pp = rp.getPickedPoint();
00982 
00983     if (pp) {
00984         SoPath *path = pp->getPath();
00985         int length = path->getLength();
00986         SoNode *tailFather = path->getNode(length-2);
00987         SoNode *tailFather2 = path->getNode(length-3);
00988 
00989         // checking if a constraint is the same as the one selected
00990         if (tailFather2 == constraint || tailFather == constraint) {
00991             return false;
00992         } else {
00993             return true;
00994         }
00995     } else {
00996         return false;
00997     }
00998 }
00999 
01000 Base::Vector3d ViewProviderSketch::seekConstraintPosition(const Base::Vector3d &suggestedPos,
01001                                                           const Base::Vector3d &dir, float step,
01002                                                           const SoNode *constraint)
01003 {
01004     int multiplier = 0;
01005     Base::Vector3d freePos;
01006     do {
01007         // Calculate new position of constraint
01008         freePos = suggestedPos + (dir * (multiplier * step));
01009         multiplier++; // Increment the multiplier
01010     }
01011     while (isConstraintAtPosition(freePos, constraint));
01012     return freePos;
01013 }
01014 
01015 bool ViewProviderSketch::isSelectable(void) const
01016 {
01017     if (isEditing())
01018         return false;
01019     else
01020         return PartGui::ViewProvider2DObject::isSelectable();
01021 }
01022 
01023 void ViewProviderSketch::onSelectionChanged(const Gui::SelectionChanges& msg)
01024 {
01025     // are we in edit?
01026     if (edit) {
01027         std::string temp;
01028         if (msg.Type == Gui::SelectionChanges::ClrSelection) {
01029             // if something selected in this object?
01030             if (edit->SelPointSet.size() > 0 || edit->SelCurvSet.size() > 0 || edit->SelCrossSet.size() > 0 || edit->SelConstraintSet.size() > 0) {
01031                 // clear our selection and update the color of the viewed edges and points
01032                 clearSelectPoints();
01033                 edit->SelCurvSet.clear();
01034                 edit->SelCrossSet.clear();
01035                 edit->SelConstraintSet.clear();
01036                 this->drawConstraintIcons();
01037                 this->updateColor();
01038             }
01039         }
01040         else if (msg.Type == Gui::SelectionChanges::AddSelection) {
01041             // is it this object??
01042             if (strcmp(msg.pDocName,getSketchObject()->getDocument()->getName())==0
01043                 && strcmp(msg.pObjectName,getSketchObject()->getNameInDocument())== 0) {
01044                     if (msg.pSubName) {
01045                         std::string shapetype(msg.pSubName);
01046                         if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") {
01047                             int index=std::atoi(&shapetype[4]);
01048                             edit->SelCurvSet.insert(index);
01049                             this->updateColor();
01050                         }
01051                         else if (shapetype.size() > 6 && shapetype.substr(0,6) == "Vertex") {
01052                             int index=std::atoi(&shapetype[6]);
01053                             addSelectPoint(index);
01054                             this->updateColor();
01055                         }
01056                         else if (shapetype == "RootPoint") {
01057                             edit->SelCrossSet.insert(0);
01058                             this->updateColor();
01059                         }
01060                         else if (shapetype == "V_Axis") {
01061                             edit->SelCrossSet.insert(2);
01062                             this->updateColor();
01063                         }
01064                         else if (shapetype == "H_Axis") {
01065                             edit->SelCrossSet.insert(1);
01066                             this->updateColor();
01067                         }
01068                         else if (shapetype.size() > 10 && shapetype.substr(0,10) == "Constraint") {
01069                             int index=std::atoi(&shapetype[10]);
01070                             edit->SelConstraintSet.insert(index);
01071                             this->drawConstraintIcons();
01072                             this->updateColor();
01073                         }
01074                     }
01075             }
01076         }
01077         else if (msg.Type == Gui::SelectionChanges::RmvSelection) {
01078             // Are there any objects selected
01079             if (edit->SelPointSet.size() > 0 || edit->SelCurvSet.size() > 0 || edit->SelConstraintSet.size() > 0) {
01080                 // is it this object??
01081                 if (strcmp(msg.pDocName,getSketchObject()->getDocument()->getName())==0
01082                     && strcmp(msg.pObjectName,getSketchObject()->getNameInDocument())== 0) {
01083                     if (msg.pSubName) {
01084                         std::string shapetype(msg.pSubName);
01085                         if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") {
01086                             int index=std::atoi(&shapetype[4]);
01087                             edit->SelCurvSet.erase(index);
01088                             this->updateColor();
01089                         }
01090                         else if (shapetype.size() > 6 && shapetype.substr(0,6) == "Vertex") {
01091                             int index=std::atoi(&shapetype[6]);
01092                             removeSelectPoint(index);
01093                             this->updateColor();
01094                         }
01095                         else if (shapetype.size() > 10 && shapetype.substr(0,10) == "Constraint") {
01096                             int index=std::atoi(&shapetype[10]);
01097                             edit->SelConstraintSet.erase(index);
01098                             this->drawConstraintIcons();
01099                             this->updateColor();
01100                         }
01101                     }
01102                 }
01103             }
01104         }
01105         else if (msg.Type == Gui::SelectionChanges::SetSelection) {
01106             // remove all items
01107             //selectionView->clear();
01108             //std::vector<SelectionSingleton::SelObj> objs = Gui::Selection().getSelection(Reason.pDocName);
01109             //for (std::vector<SelectionSingleton::SelObj>::iterator it = objs.begin(); it != objs.end(); ++it) {
01110             //    // build name
01111             //    temp = it->DocName;
01112             //    temp += ".";
01113             //    temp += it->FeatName;
01114             //    if (it->SubName && it->SubName[0] != '\0') {
01115             //        temp += ".";
01116             //        temp += it->SubName;
01117             //    }
01118             //    new QListWidgetItem(QString::fromAscii(temp.c_str()), selectionView);
01119             //}
01120         }
01121 
01122     }
01123 }
01124 
01125 bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, int &PtIndex, int &CurvIndex, int &ConstrIndex, int &CrossIndex)
01126 {
01127     assert(edit);
01128 
01129     PtIndex = -1;
01130     CurvIndex = -1;
01131     ConstrIndex = -1;
01132     CrossIndex = -1;
01133 
01134     if (Point) {
01135         //Base::Console().Log("Point pick\n");
01136         SoPath *path = Point->getPath();
01137         SoNode *tail = path->getTail();
01138         SoNode *tailFather = path->getNode(path->getLength()-2);
01139         SoNode *tailFather2 = path->getNode(path->getLength()-3);
01140 
01141         // checking for a hit in the points
01142         if (tail == edit->PointSet) {
01143             const SoDetail *point_detail = Point->getDetail(edit->PointSet);
01144             if (point_detail && point_detail->getTypeId() == SoPointDetail::getClassTypeId()) {
01145                 // get the index
01146                 PtIndex = static_cast<const SoPointDetail *>(point_detail)->getCoordinateIndex();
01147             }
01148         } else {
01149             // checking for a hit in the Curves
01150             if (tail == edit->CurveSet) {
01151                 const SoDetail *curve_detail = Point->getDetail(edit->CurveSet);
01152                 if (curve_detail && curve_detail->getTypeId() == SoLineDetail::getClassTypeId()) {
01153                     // get the index
01154                     CurvIndex = static_cast<const SoLineDetail *>(curve_detail)->getLineIndex();
01155                 }
01156             // checking for a hit in the Cross
01157             } else if (tail == edit->RootCrossSetV) {
01158                 //const SoDetail *cross_detail = Point->getDetail(edit->RootCrossSet);
01159                 //if (cross_detail && cross_detail->getTypeId() == SoLineDetail::getClassTypeId()) {
01160                     // get the index
01161                     CrossIndex = 1;
01162                 //}
01163            } else if (tail == edit->RootCrossSetH) {
01164                 //const SoDetail *cross_detail = Point->getDetail(edit->RootCrossSet);
01165                 //if (cross_detail && cross_detail->getTypeId() == SoLineDetail::getClassTypeId()) {
01166                     // get the index
01167                     CrossIndex = 2;
01168                 //}
01169             } else {
01170                 // checking if a constraint is hit
01171                 if (tailFather2 == edit->constrGroup)
01172                     for (int i=0; i < edit->constrGroup->getNumChildren(); i++)
01173                         if (edit->constrGroup->getChild(i) == tailFather) {
01174                             ConstrIndex = i;
01175                             //Base::Console().Log("Constr %d pick\n",i);
01176                             break;
01177                         }
01178             }
01179         }
01180 
01181         if (PtIndex >= 0 && PtIndex != edit->PreselectPoint) { // if a new point is hit
01182             std::stringstream ss;
01183             ss << "Vertex" << PtIndex;
01184             bool accepted =
01185             Gui::Selection().setPreselect(getSketchObject()->getDocument()->getName()
01186                                          ,getSketchObject()->getNameInDocument()
01187                                          ,ss.str().c_str()
01188                                          ,Point->getPoint()[0]
01189                                          ,Point->getPoint()[1]
01190                                          ,Point->getPoint()[2]);
01191             edit->blockedPreselection = !accepted;
01192             if (accepted) {
01193                 setPreselectPoint(PtIndex);
01194                 edit->PreselectCurve = -1;
01195                 edit->PreselectCross = -1;
01196                 edit->PreselectConstraint = -1;
01197                 if (edit->sketchHandler)
01198                     edit->sketchHandler->applyCursor();
01199                 return true;
01200             }
01201         } else if (CurvIndex >= 0 && CurvIndex != edit->PreselectCurve) {  // if a new curve is hit
01202             std::stringstream ss;
01203             ss << "Edge" << CurvIndex;
01204             bool accepted =
01205             Gui::Selection().setPreselect(getSketchObject()->getDocument()->getName()
01206                                          ,getSketchObject()->getNameInDocument()
01207                                          ,ss.str().c_str()
01208                                          ,Point->getPoint()[0]
01209                                          ,Point->getPoint()[1]
01210                                          ,Point->getPoint()[2]);
01211             edit->blockedPreselection = !accepted;
01212             if (accepted) {
01213                 resetPreselectPoint();
01214                 edit->PreselectCurve = CurvIndex;
01215                 edit->PreselectCross = -1;
01216                 edit->PreselectConstraint = -1;
01217                 if (edit->sketchHandler)
01218                     edit->sketchHandler->applyCursor();
01219                 return true;
01220             }
01221         } else if (CrossIndex >= 0 && CrossIndex != edit->PreselectCross) {
01222             std::stringstream ss;
01223             switch(CrossIndex){
01224                 case 0: ss << "RootPoint" ; break;
01225                 case 1: ss << "H_Axis"    ; break;
01226                 case 2: ss << "V_Axis"    ; break;
01227             }
01228             bool accepted =
01229             Gui::Selection().setPreselect(getSketchObject()->getDocument()->getName()
01230                                          ,getSketchObject()->getNameInDocument()
01231                                          ,ss.str().c_str()
01232                                          ,Point->getPoint()[0]
01233                                          ,Point->getPoint()[1]
01234                                          ,Point->getPoint()[2]);
01235             edit->blockedPreselection = !accepted;
01236             if (accepted) {
01237                 resetPreselectPoint();
01238                 edit->PreselectCurve = -1;
01239                 edit->PreselectCross = CrossIndex;
01240                 edit->PreselectConstraint = -1;
01241                 if (edit->sketchHandler)
01242                     edit->sketchHandler->applyCursor();
01243                 return true;
01244             }
01245         } else if (ConstrIndex >= 0 && ConstrIndex != edit->PreselectConstraint) { // if a constraint is hit
01246             std::stringstream ss;
01247             ss << "Constraint" << ConstrIndex;
01248             bool accepted =
01249             Gui::Selection().setPreselect(getSketchObject()->getDocument()->getName()
01250                                          ,getSketchObject()->getNameInDocument()
01251                                          ,ss.str().c_str()
01252                                          ,Point->getPoint()[0]
01253                                          ,Point->getPoint()[1]
01254                                          ,Point->getPoint()[2]);
01255             edit->blockedPreselection = !accepted;
01256             if (accepted) {
01257                 resetPreselectPoint();
01258                 edit->PreselectCurve = -1;
01259                 edit->PreselectCross = -1;
01260                 edit->PreselectConstraint = ConstrIndex;
01261                 if (edit->sketchHandler)
01262                     edit->sketchHandler->applyCursor();
01263                 return true;
01264             }
01265         } else if ((PtIndex < 0 && CurvIndex < 0 && CrossIndex < 0 && ConstrIndex < 0) &&
01266                    (edit->PreselectPoint >= 0 || edit->PreselectCurve >= 0 || edit->PreselectCross >= 0
01267                     || edit->PreselectConstraint >= 0 || edit->blockedPreselection)) {
01268             // we have just left a preselection
01269             resetPreselectPoint();
01270             edit->PreselectCurve = -1;
01271             edit->PreselectCross = -1;
01272             edit->PreselectConstraint = -1;
01273             edit->blockedPreselection = false;
01274             if (edit->sketchHandler)
01275                 edit->sketchHandler->applyCursor();
01276             return true;
01277         }
01278         Gui::Selection().setPreselectCoord(Point->getPoint()[0]
01279                                           ,Point->getPoint()[1]
01280                                           ,Point->getPoint()[2]);
01281     } else if (edit->PreselectCurve >= 0 || edit->PreselectPoint >= 0 ||
01282                edit->PreselectConstraint >= 0 || edit->PreselectCross >= 0 || edit->blockedPreselection) {
01283         resetPreselectPoint();
01284         edit->PreselectCurve = -1;
01285         edit->PreselectCross = -1;
01286         edit->PreselectConstraint = -1;
01287         edit->blockedPreselection = false;
01288         if (edit->sketchHandler)
01289             edit->sketchHandler->applyCursor();
01290         return true;
01291     }
01292 
01293     return false;
01294 }
01295 
01296 void ViewProviderSketch::updateColor(void)
01297 {
01298     assert(edit);
01299     //Base::Console().Log("Draw preseletion\n");
01300 
01301     int PtNum = edit->PointsMaterials->diffuseColor.getNum();
01302     SbColor *pcolor = edit->PointsMaterials->diffuseColor.startEditing();
01303     int CurvNum = edit->CurvesMaterials->diffuseColor.getNum();
01304     SbColor *color = edit->CurvesMaterials->diffuseColor.startEditing();
01305     SbColor *ccolorV = edit->RootCrossMaterialsV->diffuseColor.startEditing();
01306     SbColor *ccolorH = edit->RootCrossMaterialsH->diffuseColor.startEditing();
01307 
01308     // colors of the point set
01309     for (int  i=0; i < PtNum; i++) {
01310         if (edit->SelPointSet.find(i) != edit->SelPointSet.end())
01311             pcolor[i] = SelectColor;
01312         else if (edit->PreselectPoint == i)
01313             pcolor[i] = PreselectColor;
01314         else if (edit->FullyConstrained)
01315             pcolor[i] = FullyConstrainedColor;
01316         else
01317             pcolor[i] = VertexColor;
01318     }
01319 
01320     // colors of the curves
01321     for (int  i=0; i < CurvNum; i++) {
01322         if (edit->SelCurvSet.find(i) != edit->SelCurvSet.end())
01323             color[i] = SelectColor;
01324         else if (edit->PreselectCurve == i)
01325             color[i] = PreselectColor;
01326         else if (this->getSketchObject()->Geometry.getValues()[i]->Construction)
01327             color[i] = CurveDraftColor;
01328         else if (edit->FullyConstrained)
01329             color[i] = FullyConstrainedColor;
01330         else
01331             color[i] = CurveColor;
01332     }
01333 
01334     // colors of the cross
01335     if (edit->SelCrossSet.find(1) != edit->SelCrossSet.end())
01336         ccolorV[0] = SelectColor;
01337     else if (edit->PreselectCross == 1)
01338         ccolorV[0] = PreselectColor;
01339     else
01340         ccolorV[0] = CrossColorV;
01341 
01342     if (edit->SelCrossSet.find(2) != edit->SelCrossSet.end())
01343         ccolorH[0] = SelectColor;
01344     else if (edit->PreselectCross == 2)
01345         ccolorH[0] = PreselectColor;
01346     else
01347         ccolorH[0] = CrossColorH;
01348 
01349 
01350     // colors of the constraints
01351     for (int i=0; i < edit->constrGroup->getNumChildren(); i++) {
01352         SoSeparator *s = dynamic_cast<SoSeparator *>(edit->constrGroup->getChild(i));
01353         SoMaterial *m = dynamic_cast<SoMaterial *>(s->getChild(0));
01354 
01355         // Check Constraint Type
01356         ConstraintType type = this->getSketchObject()->Constraints.getValues()[i]->Type;
01357         bool hasDatumLabel  = (type == Sketcher::Angle ||
01358                               type == Sketcher::Radius ||
01359                               type == Sketcher::Distance || type == Sketcher::DistanceX || type == Sketcher::DistanceY);
01360 
01361         if (edit->SelConstraintSet.find(i) != edit->SelConstraintSet.end()) {
01362             m->diffuseColor = SelectColor;
01363             if (hasDatumLabel) {
01364                 SoDatumLabel *l = dynamic_cast<SoDatumLabel *>(s->getChild(4));
01365                 l->textColor = SelectColor;
01366             }
01367         } else if (edit->PreselectConstraint == i) {
01368             m->diffuseColor = PreselectColor;
01369             if (hasDatumLabel) {
01370                 SoDatumLabel *l = dynamic_cast<SoDatumLabel *>(s->getChild(4));
01371                 l->textColor = PreselectColor;
01372             }
01373         }
01374         else {
01375             m->diffuseColor = ConstrDimColor;
01376             if (hasDatumLabel) {
01377                 SoDatumLabel *l = dynamic_cast<SoDatumLabel *>(s->getChild(4));
01378                 l->textColor = ConstrDimColor;
01379             }
01380         }
01381     }
01382 
01383     // end editing
01384     edit->CurvesMaterials->diffuseColor.finishEditing();
01385     edit->PointsMaterials->diffuseColor.finishEditing();
01386     edit->RootCrossMaterialsV->diffuseColor.finishEditing();
01387     edit->RootCrossMaterialsH->diffuseColor.finishEditing();
01388 }
01389 
01390 bool ViewProviderSketch::isPointOnSketch(const SoPickedPoint *pp) const
01391 {
01392     // checks if we picked a point on the sketch or any other nodes like the grid
01393     SoPath *path = pp->getPath();
01394     return path->containsNode(edit->EditRoot);
01395 }
01396 
01397 bool ViewProviderSketch::doubleClicked(void)
01398 {
01399     Gui::Application::Instance->activeDocument()->setEdit(this);
01400     return true;
01401 }
01402 
01403 void ViewProviderSketch::drawConstraintIcons()
01404 {
01405     const std::vector<Sketcher::Constraint *> &constraints = getSketchObject()->Constraints.getValues();
01406     int constrId = 0;
01407     for (std::vector<Sketcher::Constraint *>::const_iterator it=constraints.begin();
01408          it != constraints.end(); ++it, constrId++) {
01409         // Check if Icon Should be created
01410         int index1 = 2, index2 = -1; // Index for SoImage Nodes in SoContainer
01411         QString icoType;
01412         switch((*it)->Type) {
01413         case Horizontal:
01414             icoType = QString::fromAscii("small/Constraint_Horizontal_sm");
01415             break;
01416         case Vertical:
01417             icoType = QString::fromAscii("small/Constraint_Vertical_sm");
01418             break;
01419         case PointOnObject:
01420             icoType = QString::fromAscii("small/Constraint_PointOnObject_sm");
01421             break;
01422         case Tangent:
01423             icoType = QString::fromAscii("small/Constraint_Tangent_sm");
01424             {   // second icon is available only for colinear line segments
01425                 Part::Geometry *geo1 = getSketchObject()->Geometry.getValues()[(*it)->First];
01426                 Part::Geometry *geo2 = getSketchObject()->Geometry.getValues()[(*it)->Second];
01427                 if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() &&
01428                     geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
01429                     index2 = 4;
01430                 }
01431             }
01432             break;
01433         case Parallel:
01434             icoType = QString::fromAscii("small/Constraint_Parallel_sm");
01435             index2 = 4;
01436             break;
01437         case Perpendicular:
01438             icoType = QString::fromAscii("small/Constraint_Perpendicular_sm");
01439             index2 = 4;
01440             break;
01441         case Equal:
01442             icoType = QString::fromAscii("small/Constraint_EqualLength_sm");
01443             index2 = 4;
01444             break;
01445         case Symmetric:
01446             icoType = QString::fromAscii("small/Constraint_Symmetric_sm");
01447             index1 = 3;
01448             break;
01449         default:
01450             continue; // Icon shouldn't be generated
01451         }
01452 
01453         // Constants to help create constraint icons
01454         const int constrImgSize = 16;
01455 
01456         QColor constrIcoColor((int)(ConstrIcoColor [0] * 255.0f), (int)(ConstrIcoColor[1] * 255.0f),(int)(ConstrIcoColor[2] * 255.0f));
01457         QColor constrIconSelColor ((int)(SelectColor[0] * 255.0f), (int)(SelectColor[1] * 255.0f),(int)(SelectColor[2] * 255.0f));
01458         QColor constrIconPreselColor ((int)(PreselectColor[0] * 255.0f), (int)(PreselectColor[1] * 255.0f),(int)(PreselectColor[2] * 255.0f));
01459 
01460         // Set Color for Icons
01461         QColor iconColor;
01462         if (edit->PreselectConstraint == constrId)
01463             iconColor = constrIconPreselColor;
01464         else if (edit->SelConstraintSet.find(constrId) != edit->SelConstraintSet.end())
01465             iconColor = constrIconSelColor;
01466         else
01467             iconColor = constrIcoColor;
01468 
01469         // Create Icons
01470 
01471         // Create a QPainter for the constraint icon rendering
01472         QPainter qp;
01473         QImage icon;
01474 
01475         icon = Gui::BitmapFactory().pixmap(icoType.toAscii()).toImage();
01476 
01477         // Assumes that digits are 9 pixel wide
01478         int imgwidth = icon.width() + ((index2 == -1) ? 0 : 9 * (1 + (constrId + 1)/10));
01479         QImage image = icon.copy(0, 0, imgwidth, icon.height());
01480 
01481         // Paint the Icons
01482         qp.begin(&image);
01483         qp.setCompositionMode(QPainter::CompositionMode_SourceIn);
01484         qp.fillRect(0,0, constrImgSize, constrImgSize, iconColor);
01485 
01486         // Render constraint index if necessary
01487         if (index2 != -1) {
01488             qp.setCompositionMode(QPainter::CompositionMode_SourceOver);
01489             qp.setPen(iconColor);
01490             QFont font = QApplication::font();
01491             font.setPixelSize(11);
01492             font.setBold(true);
01493             qp.setFont(font);
01494             qp.drawText(constrImgSize, image.height(), QString::number(constrId + 1));
01495         }
01496         qp.end();
01497 
01498         SoSFImage icondata = SoSFImage();
01499 
01500         Gui::BitmapFactory().convert(image, icondata);
01501 
01502         int nc = 4;
01503         SbVec2s iconSize(image.width(), image.height());
01504 
01505         // Find the Constraint Icon SoImage Node
01506         SoSeparator *sep = dynamic_cast<SoSeparator *>(edit->constrGroup->getChild(constrId));
01507         SoImage *constraintIcon1 = dynamic_cast<SoImage *>(sep->getChild(index1));
01508 
01509         constraintIcon1->image.setValue(iconSize, 4, icondata.getValue(iconSize, nc));
01510 
01511         //Set Image Alignment to Center
01512         constraintIcon1->vertAlignment = SoImage::HALF;
01513         constraintIcon1->horAlignment = SoImage::CENTER;
01514 
01515         // If more than one icon per constraint
01516         if (index2 != -1) {
01517             SoImage *constraintIcon2 = dynamic_cast<SoImage *>(sep->getChild(index2));
01518             constraintIcon2->image.setValue(iconSize, 4, icondata.getValue(iconSize, nc));
01519             //Set Image Alignment to Center
01520             constraintIcon2->vertAlignment = SoImage::HALF;
01521             constraintIcon2->horAlignment = SoImage::CENTER;
01522         }
01523     }
01524 }
01525 
01526 float ViewProviderSketch::getScaleFactor()
01527 {
01528     Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView();
01529     if (mdi && mdi->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) {
01530         Gui::View3DInventorViewer *viewer = static_cast<Gui::View3DInventor *>(mdi)->getViewer();
01531         return viewer->getCamera()->getViewVolume(viewer->getCamera()->aspectRatio.getValue()).getWorldToScreenScale(SbVec3f(0.f, 0.f, 0.f), 0.1f) / 3;
01532     } else {
01533         return 1.f;
01534     }
01535 }
01536 
01537 void ViewProviderSketch::draw(bool temp)
01538 {
01539     assert(edit);
01540 
01541     // Get Bounding box dimensions for Datum text
01542     Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView();
01543 
01544     // Render Geometry ===================================================
01545     std::vector<Base::Vector3d> Coords;
01546     std::vector<Base::Vector3d> Points;
01547     std::vector<unsigned int> Index;
01548 
01549     const std::vector<Part::Geometry *> *geomlist;
01550     std::vector<Part::Geometry *> tempGeo;
01551     if (temp) {
01552         tempGeo = edit->ActSketch.getGeometry();
01553         geomlist = &tempGeo;
01554     } else
01555         geomlist = &getSketchObject()->Geometry.getValues();
01556 
01557     for (std::vector<Part::Geometry *>::const_iterator it = geomlist->begin(); it != geomlist->end(); ++it) {
01558         if ((*it)->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { // add a line
01559             const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(*it);
01560             // create the definition struct for that geom
01561             Coords.push_back(lineSeg->getStartPoint());
01562             Coords.push_back(lineSeg->getEndPoint());
01563             Points.push_back(lineSeg->getStartPoint());
01564             Points.push_back(lineSeg->getEndPoint());
01565             Index.push_back(2);
01566         }
01567         else if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) { // add a circle
01568             const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(*it);
01569             Handle_Geom_Circle curve = Handle_Geom_Circle::DownCast(circle->handle());
01570 
01571             int countSegments = 50;
01572             Base::Vector3d center = circle->getCenter();
01573             double segment = (2 * M_PI) / countSegments;
01574             for (int i=0; i < countSegments; i++) {
01575                 gp_Pnt pnt = curve->Value(i*segment);
01576                 Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
01577             }
01578 
01579             gp_Pnt pnt = curve->Value(0);
01580             Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
01581 
01582             Index.push_back(countSegments+1);
01583             Points.push_back(center);
01584         }
01585         else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { // add an arc
01586             const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(*it);
01587             Handle_Geom_TrimmedCurve curve = Handle_Geom_TrimmedCurve::DownCast(arc->handle());
01588 
01589             double startangle, endangle;
01590             arc->getRange(startangle, endangle);
01591             if (startangle > endangle) // if arc is reversed
01592                 std::swap(startangle, endangle);
01593 
01594             double range = endangle-startangle;
01595             int countSegments = std::max(6, int(50.0 * range / (2 * M_PI)));
01596             double segment = range / countSegments;
01597 
01598             Base::Vector3d center = arc->getCenter();
01599             Base::Vector3d start  = arc->getStartPoint();
01600             Base::Vector3d end    = arc->getEndPoint();
01601 
01602             for (int i=0; i < countSegments; i++) {
01603                 gp_Pnt pnt = curve->Value(startangle);
01604                 Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
01605                 startangle += segment;
01606             }
01607 
01608             // end point
01609             gp_Pnt pnt = curve->Value(endangle);
01610             Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
01611 
01612             Index.push_back(countSegments+1);
01613             Points.push_back(center);
01614             Points.push_back(start);
01615             Points.push_back(end);
01616         }
01617         else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a circle
01618             const Part::GeomBSplineCurve *spline = dynamic_cast<const Part::GeomBSplineCurve *>(*it);
01619             Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(spline->handle());
01620 
01621             double first = curve->FirstParameter();
01622             double last = curve->LastParameter();
01623             if (first > last) // if arc is reversed
01624                 std::swap(first, last);
01625 
01626             double range = last-first;
01627             int countSegments = 50;
01628             double segment = range / countSegments;
01629 
01630             for (int i=0; i < countSegments; i++) {
01631                 gp_Pnt pnt = curve->Value(first);
01632                 Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
01633                 first += segment;
01634             }
01635 
01636             // end point
01637             gp_Pnt end = curve->Value(last);
01638             Coords.push_back(Base::Vector3d(end.X(), end.Y(), end.Z()));
01639 
01640             std::vector<Base::Vector3d> poles = spline->getPoles();
01641             for (std::vector<Base::Vector3d>::iterator it = poles.begin(); it != poles.end(); ++it) {
01642                 Points.push_back(*it);
01643             }
01644 
01645             Index.push_back(countSegments+1);
01646         }
01647         else {
01648             ;
01649         }
01650     }
01651 
01652     edit->CurvesCoordinate->point.setNum(Coords.size());
01653     edit->CurveSet->numVertices.setNum(Index.size());
01654     edit->CurvesMaterials->diffuseColor.setNum(Index.size());
01655     edit->PointsCoordinate->point.setNum(Points.size());
01656     edit->PointsMaterials->diffuseColor.setNum(Points.size());
01657 
01658     SbVec3f *verts = edit->CurvesCoordinate->point.startEditing();
01659     int32_t *index = edit->CurveSet->numVertices.startEditing();
01660     SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
01661 
01662     // set cross coordinates
01663     edit->RootCrossSetV->numVertices.set1Value(0,2);
01664     edit->RootCrossSetH->numVertices.set1Value(0,2);
01665 
01666     float MiX = -exp(ceil(log(std::abs(MinX))));
01667     MiX = std::min(MiX,(float)-exp(ceil(log(std::abs(0.1f*MaxX)))));
01668     float MaX = exp(ceil(log(std::abs(MaxX))));
01669     MaX = std::max(MaX,(float)exp(ceil(log(std::abs(0.1f*MinX)))));
01670     float MiY = -exp(ceil(log(std::abs(MinY))));
01671     MiY = std::min(MiY,(float)-exp(ceil(log(std::abs(0.1f*MaxY)))));
01672     float MaY = exp(ceil(log(std::abs(MaxY))));
01673     MaY = std::max(MaY,(float)exp(ceil(log(std::abs(0.1f*MinY)))));
01674 
01675     edit->RootCrossCoordinateV->point.set1Value(0,SbVec3f(MiX, 0.0f, zCross));
01676     edit->RootCrossCoordinateV->point.set1Value(1,SbVec3f(MaX, 0.0f, zCross));
01677     edit->RootCrossCoordinateH->point.set1Value(0,SbVec3f(0.0f, MiY, zCross));
01678     edit->RootCrossCoordinateH->point.set1Value(1,SbVec3f(0.0f, MaY, zCross));
01679 
01680     int i=0; // setting up the line set
01681     for (std::vector<Base::Vector3d>::const_iterator it = Coords.begin(); it != Coords.end(); ++it,i++)
01682         verts[i].setValue(it->x,it->y,zLines);
01683 
01684     i=0; // setting up the indexes of the line set
01685     for (std::vector<unsigned int>::const_iterator it = Index.begin(); it != Index.end(); ++it,i++)
01686         index[i] = *it;
01687 
01688 
01689     i=0; // setting up the point set
01690     for (std::vector<Base::Vector3d>::const_iterator it = Points.begin(); it != Points.end(); ++it,i++)
01691         pverts[i].setValue(it->x,it->y,zPoints);
01692 
01693 
01694     edit->CurvesCoordinate->point.finishEditing();
01695     edit->CurveSet->numVertices.finishEditing();
01696     edit->PointsCoordinate->point.finishEditing();
01697 
01698     // Render Constraints ===================================================
01699     const std::vector<Sketcher::Constraint *> &ConStr = getSketchObject()->Constraints.getValues();
01700     // After an undo/redo it can happen that we have an empty geometry list but a non-empty constraint list
01701     // In this case just ignore the constraints. (See bug #0000421)
01702     if (geomlist->empty() && !ConStr.empty()) {
01703         rebuildConstraintsVisual();
01704         return;
01705     }
01706     // reset point if the constraint type has changed
01707 Restart:
01708     // check if a new constraint arrived
01709     if (ConStr.size() != edit->vConstrType.size())
01710         rebuildConstraintsVisual();
01711     assert(int(ConStr.size()) == edit->constrGroup->getNumChildren());
01712     assert(int(edit->vConstrType.size()) == edit->constrGroup->getNumChildren());
01713     // go through the constraints and update the position
01714     i = 0;
01715     for (std::vector<Sketcher::Constraint *>::const_iterator it = ConStr.begin(); it != ConStr.end(); ++it,i++) {
01716         // check if the type has changed
01717         if ((*it)->Type != edit->vConstrType[i]) {
01718             // clearing the type vector will force a rebuild of the visual nodes
01719             edit->vConstrType.clear();
01720             goto Restart;
01721         }
01722         // root separator for this constraint
01723         SoSeparator *sep = dynamic_cast<SoSeparator *>(edit->constrGroup->getChild(i));
01724         const Constraint *Constr = *it;
01725 
01726         // distinquish different constraint types to build up
01727         switch (Constr->Type) {
01728             case Horizontal: // write the new position of the Horizontal constraint Same as vertical position.
01729             case Vertical: // write the new position of the Vertical constraint
01730                 {
01731                     assert(Constr->First < int(geomlist->size()));
01732                     // get the geometry
01733                     const Part::Geometry *geo = (*geomlist)[Constr->First];
01734                     // Vertical can only be a GeomLineSegment
01735                     assert(geo->getTypeId() == Part::GeomLineSegment::getClassTypeId());
01736                     const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geo);
01737 
01738                     // calculate the half distance between the start and endpoint
01739                     Base::Vector3d midpos = ((lineSeg->getEndPoint()+lineSeg->getStartPoint())/2);
01740 
01741                     //Get a set of vectors perpendicular and tangential to these
01742                     Base::Vector3d dir = (lineSeg->getEndPoint()-lineSeg->getStartPoint()).Normalize();
01743                     Base::Vector3d norm(-dir.y,dir.x,0);
01744 
01745                     float scale = dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->getScaleFactor();
01746                     Base::Vector3d constrPos = midpos + (norm * 2.5 * scale);
01747 
01748                     constrPos = seekConstraintPosition(constrPos, dir, 2.5 * scale, edit->constrGroup->getChild(i));
01749 
01750                     // Translate the Icon based on calculated position
01751                     Base::Vector3d relPos = constrPos - midpos; // Relative Position of Icons to Midpoint
01752                     relPos = relPos / scale; // Must Divide by Scale Factor
01753 
01754                     dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->abPos = SbVec3f(midpos.x, midpos.y, zConstr); //Absolute Reference
01755 
01756                     //Reference Position that is scaled according to zoom
01757                     dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relPos.x, relPos.y, 0);
01758 
01759                 }
01760                 break;
01761             case Parallel:
01762             case Perpendicular:
01763             case Equal:
01764                 {
01765                     assert(Constr->First < int(geomlist->size()));
01766                     assert(Constr->Second < int(geomlist->size()));
01767                     // get the geometry
01768                     const Part::Geometry *geo1 = (*geomlist)[Constr->First];
01769                     const Part::Geometry *geo2 = (*geomlist)[Constr->Second];
01770 
01771                     Base::Vector3d midpos1, dir1, norm1;
01772                     Base::Vector3d midpos2, dir2, norm2;
01773                     if (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() ||
01774                         geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) {
01775                         if (Constr->Type == Equal) {
01776                             double r1,r2,angle1,angle2;
01777                             if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) {
01778                                 const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo1);
01779                                 r1 = circle->getRadius();
01780                                 angle1 = M_PI/4;
01781                                 midpos1 = circle->getCenter();
01782                             } else if (geo1->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
01783                                 const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(geo1);
01784                                 r1 = arc->getRadius();
01785                                 double startangle, endangle;
01786                                 arc->getRange(startangle, endangle);
01787                                 angle1 = (startangle + endangle)/2;
01788                                 midpos1 = arc->getCenter();
01789                             } else
01790                                 break;
01791 
01792                             if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) {
01793                                 const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo2);
01794                                 r2 = circle->getRadius();
01795                                 angle2 = M_PI/4;
01796                                 midpos2 = circle->getCenter();
01797                             } else if (geo2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
01798                                 const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(geo2);
01799                                 r2 = arc->getRadius();
01800                                 double startangle, endangle;
01801                                 arc->getRange(startangle, endangle);
01802                                 angle2 = (startangle + endangle)/2;
01803                                 midpos2 = arc->getCenter();
01804                             } else
01805                                 break;
01806 
01807                             norm1 = Base::Vector3d(cos(angle1),sin(angle1),0);
01808                             dir1 = Base::Vector3d(-norm1.y,norm1.x,0);
01809                             midpos1 += r1*norm1;
01810 
01811                             norm2 = Base::Vector3d(cos(angle2),sin(angle2),0);
01812                             dir2 = Base::Vector3d(-norm2.y,norm2.x,0);
01813                             midpos2 += r2*norm2;
01814                         } else // Parallel or Perpendicular can only apply to a GeomLineSegment
01815                             break;
01816                     } else {
01817                         const Part::GeomLineSegment *lineSeg1 = dynamic_cast<const Part::GeomLineSegment *>(geo1);
01818                         const Part::GeomLineSegment *lineSeg2 = dynamic_cast<const Part::GeomLineSegment *>(geo2);
01819 
01820                         // calculate the half distance between the start and endpoint
01821                         midpos1 = ((lineSeg1->getEndPoint()+lineSeg1->getStartPoint())/2);
01822                         midpos2 = ((lineSeg2->getEndPoint()+lineSeg2->getStartPoint())/2);
01823                         //Get a set of vectors perpendicular and tangential to these
01824                         dir1 = (lineSeg1->getEndPoint()-lineSeg1->getStartPoint()).Normalize();
01825                         dir2 = (lineSeg2->getEndPoint()-lineSeg2->getStartPoint()).Normalize();
01826                         norm1 = Base::Vector3d(-dir1.y,dir1.x,0.);
01827                         norm2 = Base::Vector3d(-dir2.y,dir2.x,0.);
01828                     }
01829 
01830                     // Get Current Scale Factor
01831                     float scale = dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->getScaleFactor();
01832 
01833                     Base::Vector3d constrPos1 = midpos1 + (norm1 * scale * 2.5 );
01834                     constrPos1 = seekConstraintPosition(constrPos1, dir1, scale * 2.5, edit->constrGroup->getChild(i));
01835 
01836                     Base::Vector3d constrPos2 = midpos2 + (norm2 * scale * 2.5);
01837                     constrPos2 = seekConstraintPosition(constrPos2, dir2, scale * 2.5, edit->constrGroup->getChild(i));
01838 
01839                     // Translate the Icon based on calculated position
01840                     Base::Vector3d relPos1 = constrPos1 - midpos1 ; // Relative Position of Icons to Midpoint1
01841                     Base::Vector3d relPos2 = constrPos2 - midpos2 ; // Relative Position of Icons to Midpoint2
01842 
01843                     relPos1 = relPos1 / scale;
01844                     relPos2 = relPos2 / scale;
01845 
01846                     dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->abPos = SbVec3f(midpos1.x, midpos1.y, zConstr); //Absolute Reference
01847 
01848                     //Reference Position that is scaled according to zoom
01849                     dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relPos1.x, relPos1.y, 0);
01850 
01851                     Base::Vector3d secondPos = midpos2 - midpos1;
01852                     dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->abPos = SbVec3f(secondPos.x, secondPos.y, zConstr); //Absolute Reference
01853 
01854                     //Reference Position that is scaled according to zoom
01855                     dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->translation = SbVec3f(relPos2.x -relPos1.x, relPos2.y -relPos1.y, 0);
01856 
01857                 }
01858                 break;
01859             case Distance:
01860             case DistanceX:
01861             case DistanceY:
01862                 {
01863                     assert(Constr->First < int(geomlist->size()));
01864 
01865                     Base::Vector3d pnt1(0.,0.,0.), pnt2(0.,0.,0.);
01866                     if (Constr->SecondPos != Sketcher::none) { // point to point distance
01867                         if (temp) {
01868                             pnt1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos);
01869                             pnt2 = edit->ActSketch.getPoint(Constr->Second, Constr->SecondPos);
01870                         } else {
01871                             pnt1 = getSketchObject()->getPoint(Constr->First, Constr->FirstPos);
01872                             pnt2 = getSketchObject()->getPoint(Constr->Second, Constr->SecondPos);
01873                         }
01874                     } else if (Constr->Second != Constraint::GeoUndef) { // point to line distance
01875                         if (temp) {
01876                             pnt1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos);
01877                         } else {
01878                             pnt1 = getSketchObject()->getPoint(Constr->First, Constr->FirstPos);
01879                         }
01880                         const Part::Geometry *geo = (*geomlist)[Constr->Second];
01881                         if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
01882                             const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geo);
01883                             Base::Vector3d l2p1 = lineSeg->getStartPoint();
01884                             Base::Vector3d l2p2 = lineSeg->getEndPoint();
01885                             // calculate the projection of p1 onto line2
01886                             pnt2.ProjToLine(pnt1-l2p1, l2p2-l2p1);
01887                             pnt2 += pnt1;
01888                         } else
01889                             break;
01890                     } else if (Constr->FirstPos != Sketcher::none) {
01891                         if (temp) {
01892                             pnt2 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos);
01893                         } else {
01894                             pnt2 = getSketchObject()->getPoint(Constr->First, Constr->FirstPos);
01895                         }
01896                     } else if (Constr->First != Constraint::GeoUndef) {
01897                         const Part::Geometry *geo = (*geomlist)[Constr->First];
01898                         if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
01899                             const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geo);
01900                             pnt1 = lineSeg->getStartPoint();
01901                             pnt2 = lineSeg->getEndPoint();
01902                         } else
01903                             break;
01904                     } else
01905                         break;
01906 
01907                     SbVec3f p1(pnt1.x,pnt1.y,zConstr);
01908                     SbVec3f p2(pnt2.x,pnt2.y,zConstr);
01909 
01910                     SbVec3f dir, norm;
01911                     if (Constr->Type == Distance)
01912                         dir = (p2-p1);
01913                     else if (Constr->Type == DistanceX)
01914                         dir = SbVec3f( (pnt2.x - pnt1.x >= FLT_EPSILON) ? 1 : -1, 0, 0);
01915                     else if (Constr->Type == DistanceY)
01916                         dir = SbVec3f(0, (pnt2.y - pnt1.y >= FLT_EPSILON) ? 1 : -1, 0);
01917                     dir.normalize();
01918                     norm = SbVec3f (-dir[1],dir[0],0);
01919 
01920                     // when the datum line is not parallel to p1-p2 the projection of
01921                     // p1-p2 on norm is not zero, p2 is considered as reference and p1
01922                     // is replaced by its projection p1_
01923                     float normproj12 = (p2-p1).dot(norm);
01924 
01925                     SbVec3f p1_ = p1 + normproj12 * norm;
01926                     SbVec3f midpos = (p1_ + p2)/2;
01927 
01928                     SoDatumLabel *asciiText = dynamic_cast<SoDatumLabel *>(sep->getChild(4));
01929                     if ((Constr->Type == DistanceX || Constr->Type == DistanceY) &&
01930                         Constr->FirstPos != Sketcher::none && Constr->Second == Constraint::GeoUndef)
01931                         // display negative sign for absolute coordinates
01932                         asciiText->string = SbString().sprintf("%.2f",Constr->Value);
01933                     else // hide negative sign
01934                         asciiText->string = SbString().sprintf("%.2f",std::abs(Constr->Value));
01935 
01936                     // Get Bounding box dimensions for Datum text
01937                     Gui::View3DInventorViewer *viewer = static_cast<Gui::View3DInventor *>(mdi)->getViewer();
01938 
01939                     // [FIX ME] Its an attempt to find the height of the text using the bounding box, but is in correct.
01940                     SoGetBoundingBoxAction bbAction(viewer->getViewportRegion());
01941                     bbAction.apply(sep->getChild(4));
01942 
01943                     float bx,by,bz;
01944                     bbAction.getBoundingBox().getSize(bx,by,bz);
01945                     SbVec3f textBB(bx,by,bz);
01946                     // bbAction.setCenter(, true)
01947                     // This is the bounding box containing the width and height of text
01948 
01949                     SbVec3f textBBCenter = bbAction.getBoundingBox().getCenter();
01950 
01951                     float length = Constr->LabelDistance;
01952 
01953                     // Get magnitude of angle between horizontal
01954                     double angle = atan2f(dir[1],dir[0]);
01955                     bool flip=false;
01956                     if (angle > M_PI_2+M_PI/12) {
01957                         angle -= M_PI;
01958                         flip = true;
01959                     } else if (angle <= -M_PI_2+M_PI/12) {
01960                         angle += M_PI;
01961                         flip = true;
01962                     }
01963 
01964                     SbVec3f textpos = midpos + norm * (length + ( (flip ? 1:-1) * textBBCenter[1] / 4));
01965 
01966                     // set position and rotation of Datums Text
01967                     SoTransform *transform = dynamic_cast<SoTransform *>(sep->getChild(2));
01968                     transform->rotation.setValue(SbVec3f(0, 0, 1), (float)angle);
01969                     transform->translation.setValue(textpos);
01970 
01971                     // Get the datum nodes
01972                     SoSeparator *sepDatum = dynamic_cast<SoSeparator *>(sep->getChild(1));
01973                     SoCoordinate3 *datumCord = dynamic_cast<SoCoordinate3 *>(sepDatum->getChild(0));
01974 
01975                     // [Fixme] This should be made neater - compute the vertical datum line length
01976                     float offset1 = (length + normproj12 < 0) ? -0.5  : 0.5;
01977                     float offset2 = (length < 0) ? -0.5  : 0.5;
01978                     offset1 *= getScaleFactor();
01979                     offset2 *= getScaleFactor();
01980                     // Calculate coordinates for perpendicular datum lines
01981                     datumCord->point.set1Value(0,p1);
01982                     datumCord->point.set1Value(1,p1_ + norm * (length + offset1));
01983                     datumCord->point.set1Value(2,p2);
01984                     datumCord->point.set1Value(3,p2  + norm * (length + offset2));
01985 
01986                     // Calculate the coordinates for the parallel datum lines
01987                     datumCord->point.set1Value(4,p1_    + norm * length);
01988                     datumCord->point.set1Value(5,midpos + norm * length - dir * (textBB[0]/1.7f) );
01989                     datumCord->point.set1Value(6,midpos + norm * length + dir * (textBB[0]/1.7f) );
01990                     datumCord->point.set1Value(7,p2     + norm * length);
01991 
01992                     // Use the coordinates calculated earlier to the lineset
01993                     SoLineSet *datumLineSet = dynamic_cast<SoLineSet *>(sepDatum->getChild(1));
01994                     datumLineSet->numVertices.set1Value(0,2);
01995                     datumLineSet->numVertices.set1Value(1,2);
01996                     datumLineSet->numVertices.set1Value(2,2);
01997                     datumLineSet->numVertices.set1Value(3,2);
01998                 }
01999                 break;
02000             case PointOnObject:
02001             case Tangent:
02002                 {
02003                     assert(Constr->First < int(geomlist->size()));
02004                     assert(Constr->Second < int(geomlist->size()));
02005 
02006                     Base::Vector3d pos, relPos;
02007                     if (Constr->Type == PointOnObject) {
02008                         pos = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos);
02009                         relPos = Base::Vector3d(0.f, 1.f, 0.f);
02010                         dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->abPos = SbVec3f(pos.x, pos.y, zConstr); //Absolute Reference
02011                         dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relPos.x, relPos.y, 0);
02012                     }
02013                     else if (Constr->Type == Tangent) {
02014                         // get the geometry
02015                         const Part::Geometry *geo1 = (*geomlist)[Constr->First];
02016                         const Part::Geometry *geo2 = (*geomlist)[Constr->Second];
02017 
02018                         if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() &&
02019                             geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
02020                             const Part::GeomLineSegment *lineSeg1 = dynamic_cast<const Part::GeomLineSegment *>(geo1);
02021                             const Part::GeomLineSegment *lineSeg2 = dynamic_cast<const Part::GeomLineSegment *>(geo2);
02022                             // tangency between two lines
02023                             Base::Vector3d midpos1 = ((lineSeg1->getEndPoint()+lineSeg1->getStartPoint())/2);
02024                             Base::Vector3d midpos2 = ((lineSeg2->getEndPoint()+lineSeg2->getStartPoint())/2);
02025                             Base::Vector3d dir1 = (lineSeg1->getEndPoint()-lineSeg1->getStartPoint()).Normalize();
02026                             Base::Vector3d dir2 = (lineSeg2->getEndPoint()-lineSeg2->getStartPoint()).Normalize();
02027                             Base::Vector3d norm1 = Base::Vector3d(-dir1.y,dir1.x,0.f);
02028                             Base::Vector3d norm2 = Base::Vector3d(-dir2.y,dir2.x,0.f);
02029 
02030                             // Get Current Scale Factor
02031                             float scale = dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->getScaleFactor();
02032 
02033                             Base::Vector3d constrPos1 = midpos1 + (norm1 * scale * 2.5);
02034                             constrPos1 = seekConstraintPosition(constrPos1, dir1, scale * 2.5, edit->constrGroup->getChild(i));
02035 
02036                             Base::Vector3d constrPos2 = midpos2 + (norm2 * scale * 2.5);
02037                             constrPos2 = seekConstraintPosition(constrPos2, dir2, scale * 2.5, edit->constrGroup->getChild(i));
02038 
02039                             // Translate the Icon based on calculated position
02040                             Base::Vector3d relPos1 = constrPos1 - midpos1 ; // Relative Position of Icons to Midpoint1
02041                             Base::Vector3d relPos2 = constrPos2 - midpos2 ; // Relative Position of Icons to Midpoint2
02042 
02043                             relPos1 = relPos1 / scale;
02044                             relPos2 = relPos2 / scale;
02045 
02046                             dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->abPos = SbVec3f(midpos1.x, midpos1.y, zConstr); //Absolute Reference
02047 
02048                             //Reference Position that is scaled according to zoom
02049                             dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relPos1.x, relPos1.y, 0);
02050 
02051                             Base::Vector3d secondPos = midpos2 - midpos1;
02052                             dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->abPos = SbVec3f(secondPos.x, secondPos.y, zConstr); //Absolute Reference
02053 
02054                             //Reference Position that is scaled according to zoom
02055                             dynamic_cast<SoZoomTranslation *>(sep->getChild(3))->translation = SbVec3f(relPos2.x -relPos1.x, relPos2.y -relPos1.y, 0);
02056 
02057                             break;
02058                         }
02059                         else if (geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
02060                             std::swap(geo1,geo2);
02061                         }
02062 
02063                         if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
02064                             const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geo1);
02065                             Base::Vector3d dir = (lineSeg->getEndPoint() - lineSeg->getStartPoint()).Normalize();
02066                             Base::Vector3d norm(-dir.y, dir.x, 0);
02067                             if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) {
02068                                 const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo2);
02069                                 // tangency between a line and a circle
02070                                 float length = (circle->getCenter() - lineSeg->getStartPoint())*dir;
02071 
02072                                 pos = lineSeg->getStartPoint() + dir * length;
02073                                 relPos = norm * 1;
02074                             }
02075                             else if (geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) {
02076                                 const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(geo2);
02077                                 // tangency between a line and an arc
02078                                 float length = (arc->getCenter() - lineSeg->getStartPoint())*dir;
02079 
02080                                 pos = lineSeg->getStartPoint() + dir * length;
02081                                 relPos = norm * 1;
02082                             }
02083                         }
02084 
02085                         if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId() &&
02086                             geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) {
02087                             const Part::GeomCircle *circle1 = dynamic_cast<const Part::GeomCircle *>(geo1);
02088                             const Part::GeomCircle *circle2 = dynamic_cast<const Part::GeomCircle *>(geo2);
02089                             // tangency between two cicles
02090                         }
02091                         else if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) {
02092                             std::swap(geo1,geo2);
02093                         }
02094 
02095                         if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId()) {
02096                             const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo1);
02097                             if (geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) {
02098                                 const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(geo2);
02099                                 // tangency between a circle and an arc
02100                             }
02101                         }
02102 
02103                         if (geo1->getTypeId()== Part::GeomArcOfCircle::getClassTypeId() &&
02104                             geo1->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) {
02105                             const Part::GeomArcOfCircle *arc1 = dynamic_cast<const Part::GeomArcOfCircle *>(geo1);
02106                             const Part::GeomArcOfCircle *arc2 = dynamic_cast<const Part::GeomArcOfCircle *>(geo2);
02107                             // tangency between two arcs
02108                         }
02109                         dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->abPos = SbVec3f(pos.x, pos.y, zConstr); //Absolute Reference
02110                         dynamic_cast<SoZoomTranslation *>(sep->getChild(1))->translation = SbVec3f(relPos.x, relPos.y, 0);
02111                     }
02112                 }
02113                 break;
02114             case Symmetric:
02115                 {
02116                     assert(Constr->First < int(geomlist->size()));
02117                     assert(Constr->Second < int(geomlist->size()));
02118 
02119                     Base::Vector3d pnt1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos);
02120                     Base::Vector3d pnt2 = edit->ActSketch.getPoint(Constr->Second, Constr->SecondPos);
02121 
02122                     SbVec3f p1(pnt1.x,pnt1.y,zConstr);
02123                     SbVec3f p2(pnt2.x,pnt2.y,zConstr);
02124                     SbVec3f dir = (p2-p1);
02125                     dir.normalize();
02126                     SbVec3f norm (-dir[1],dir[0],0);
02127 
02128                     // Get the datum nodes
02129                     SoSeparator *sepArrows = dynamic_cast<SoSeparator *>(sep->getChild(1));
02130                     SoCoordinate3 *arrowsCord = dynamic_cast<SoCoordinate3 *>(sepArrows->getChild(0));
02131 
02132                     arrowsCord->point.setNum(10);
02133 
02134                     // Calculate coordinates for the first arrow
02135                     arrowsCord->point.set1Value(0,p1);
02136                     arrowsCord->point.set1Value(1,p1 + dir * 5);
02137                     arrowsCord->point.set1Value(2,p1 + dir * 3 + norm * 2);
02138                     arrowsCord->point.set1Value(3,p1 + dir * 5);
02139                     arrowsCord->point.set1Value(4,p1 + dir * 3 - norm * 2);
02140 
02141                     // Calculate coordinates for the second arrow
02142                     arrowsCord->point.set1Value(5,p2);
02143                     arrowsCord->point.set1Value(6,p2 - dir * 5);
02144                     arrowsCord->point.set1Value(7,p2 - dir * 3 + norm * 2);
02145                     arrowsCord->point.set1Value(8,p2 - dir * 5);
02146                     arrowsCord->point.set1Value(9,p2 - dir * 3 - norm * 2);
02147 
02148                     // Use the coordinates calculated earlier to the lineset
02149                     SoLineSet *arrowsLineSet = dynamic_cast<SoLineSet *>(sepArrows->getChild(1));
02150                     arrowsLineSet->numVertices.set1Value(0,3);
02151                     arrowsLineSet->numVertices.set1Value(1,2);
02152                     arrowsLineSet->numVertices.set1Value(2,3);
02153                     arrowsLineSet->numVertices.set1Value(3,2);
02154 
02155                     dynamic_cast<SoTranslation *>(sep->getChild(2))->translation = (p1 + p2)/2;
02156                 }
02157                 break;
02158             case Angle:
02159                 {
02160                     assert(Constr->First < int(geomlist->size()));
02161                     assert(Constr->Second < int(geomlist->size()));
02162 
02163                     SbVec3f p0;
02164                     double startangle,range,endangle;
02165                     if (Constr->Second != Constraint::GeoUndef) {
02166                         const Part::Geometry *geo1 = (*geomlist)[Constr->First];
02167                         const Part::Geometry *geo2 = (*geomlist)[Constr->Second];
02168                         if (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() ||
02169                             geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId())
02170                             break;
02171                         const Part::GeomLineSegment *lineSeg1 = dynamic_cast<const Part::GeomLineSegment *>(geo1);
02172                         const Part::GeomLineSegment *lineSeg2 = dynamic_cast<const Part::GeomLineSegment *>(geo2);
02173 
02174                         bool flip1 = (Constr->FirstPos == end);
02175                         bool flip2 = (Constr->SecondPos == end);
02176                         Base::Vector3d dir1 = (flip1 ? -1. : 1.) * (lineSeg1->getEndPoint()-lineSeg1->getStartPoint());
02177                         Base::Vector3d dir2 = (flip2 ? -1. : 1.) * (lineSeg2->getEndPoint()-lineSeg2->getStartPoint());
02178                         Base::Vector3d pnt1 = flip1 ? lineSeg1->getEndPoint() : lineSeg1->getStartPoint();
02179                         Base::Vector3d pnt2 = flip2 ? lineSeg2->getEndPoint() : lineSeg2->getStartPoint();
02180 
02181                         // line-line intersection
02182                         {
02183                             double det = dir1.x*dir2.y - dir1.y*dir2.x;
02184                             if ((det > 0 ? det : -det) < 1e-10)
02185                                 break;
02186                             double c1 = dir1.y*pnt1.x - dir1.x*pnt1.y;
02187                             double c2 = dir2.y*pnt2.x - dir2.x*pnt2.y;
02188                             double x = (dir1.x*c2 - dir2.x*c1)/det;
02189                             double y = (dir1.y*c2 - dir2.y*c1)/det;
02190                             p0 = SbVec3f(x,y,0);
02191                         }
02192 
02193                         startangle = atan2(dir1.y,dir1.x);
02194                         range = atan2(-dir1.y*dir2.x+dir1.x*dir2.y,
02195                                       dir1.x*dir2.x+dir1.y*dir2.y);
02196                         endangle = startangle + range;
02197 
02198                     } else if (Constr->First != Constraint::GeoUndef) {
02199                         const Part::Geometry *geo = (*geomlist)[Constr->First];
02200                         if (geo->getTypeId() != Part::GeomLineSegment::getClassTypeId())
02201                             break;
02202                         const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geo);
02203 
02204                         p0 = Base::convertTo<SbVec3f>((lineSeg->getEndPoint()+lineSeg->getStartPoint())/2);
02205 
02206                         Base::Vector3d dir = lineSeg->getEndPoint()-lineSeg->getStartPoint();
02207                         startangle = 0.;
02208                         range = atan2(dir.y,dir.x);
02209                         endangle = startangle + range;
02210                     } else
02211                         break;
02212 
02213                     SoDatumLabel *asciiText = dynamic_cast<SoDatumLabel *>(sep->getChild(4));
02214                     asciiText->string = SbString().sprintf("%.2f",Base::toDegrees<double>(std::abs(Constr->Value)));
02215 
02216                     // Get Bounding box dimensions for Datum text
02217                     Gui::View3DInventorViewer *viewer = static_cast<Gui::View3DInventor *>(mdi)->getViewer();
02218 
02219                     // [FIX ME] Its an attempt to find the height of the text using the bounding box, but is in correct.
02220                     SoGetBoundingBoxAction bbAction(viewer->getViewportRegion());
02221                     bbAction.apply(sep->getChild(4));
02222 
02223                     float bx,by,bz;
02224                     bbAction.getBoundingBox().getSize(bx,by,bz);
02225                     SbVec3f textBB(bx,by,bz);
02226 
02227                     SbVec3f textBBCenter = bbAction.getBoundingBox().getCenter();
02228 
02229                     float length = Constr->LabelDistance;
02230                     float r = 2*length;
02231 
02232                     SbVec3f v0(cos(startangle+range/2),sin(startangle+range/2),0);
02233                     SbVec3f textpos = p0 + v0 * r - SbVec3f(0,1,0) * textBBCenter[1]/4;
02234 
02235                     // leave some space for the text
02236                     if (range >= 0)
02237                         range = std::max(0.2*range, range - textBB[0]/(2*r));
02238                     else
02239                         range = std::min(0.2*range, range + textBB[0]/(2*r));
02240 
02241                     int countSegments = std::max(6, abs(int(50.0 * range / (2 * M_PI))));
02242                     double segment = range / (2*countSegments-2);
02243 
02244                     // set position and rotation of Datums Text
02245                     SoTransform *transform = dynamic_cast<SoTransform *>(sep->getChild(2));
02246                     transform->translation.setValue(textpos);
02247 
02248                     // Get the datum nodes
02249                     SoSeparator *sepDatum = dynamic_cast<SoSeparator *>(sep->getChild(1));
02250                     SoCoordinate3 *datumCord = dynamic_cast<SoCoordinate3 *>(sepDatum->getChild(0));
02251 
02252                     datumCord->point.setNum(2*countSegments+4);
02253                     int i=0;
02254                     int j=2*countSegments-1;
02255                     for (; i < countSegments; i++, j--) {
02256                         double angle = startangle + segment*i;
02257                         datumCord->point.set1Value(i,p0+SbVec3f(r*cos(angle),r*sin(angle),0));
02258                         angle = endangle - segment*i;
02259                         datumCord->point.set1Value(j,p0+SbVec3f(r*cos(angle),r*sin(angle),0));
02260                     }
02261                     SbVec3f v1(cos(startangle),sin(startangle),0);
02262                     SbVec3f v2(cos(endangle),sin(endangle),0);
02263                     float sf = getScaleFactor();
02264                     datumCord->point.set1Value(2*countSegments  ,p0+(r-0.5f * sf)*v1);
02265                     datumCord->point.set1Value(2*countSegments+1,p0+(r+0.5f * sf)*v1);
02266                     datumCord->point.set1Value(2*countSegments+2,p0+(r-0.5f * sf)*v2);
02267                     datumCord->point.set1Value(2*countSegments+3,p0+(r+0.5f * sf)*v2);
02268 
02269                     // Use the coordinates calculated earlier to the lineset
02270                     SoLineSet *datumLineSet = dynamic_cast<SoLineSet *>(sepDatum->getChild(1));
02271                     datumLineSet->numVertices.set1Value(0,countSegments);
02272                     datumLineSet->numVertices.set1Value(1,countSegments);
02273                     datumLineSet->numVertices.set1Value(2,2);
02274                     datumLineSet->numVertices.set1Value(3,2);
02275                 }
02276                 break;
02277             case Radius:
02278                 {
02279                     assert(Constr->First < int(geomlist->size()));
02280 
02281                     Base::Vector3d pnt1(0.,0.,0.), pnt2(0.,0.,0.);
02282                     if (Constr->First != Constraint::GeoUndef) {
02283                         const Part::Geometry *geo = (*geomlist)[Constr->First];
02284 
02285                         if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
02286                             const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>(geo);
02287                             double radius = arc->getRadius();
02288                             double startangle, endangle;
02289                             arc->getRange(startangle, endangle);
02290                             double angle = (startangle + endangle)/2;
02291                             pnt1 = arc->getCenter();
02292                             pnt2 = pnt1 + radius * Base::Vector3d(cos(angle),sin(angle),0.);
02293                         }
02294                         else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
02295                             const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>(geo);
02296                             double radius = circle->getRadius();
02297                             double angle = M_PI/4;
02298                             pnt1 = circle->getCenter();
02299                             pnt2 = pnt1 + radius * Base::Vector3d(cos(angle),sin(angle),0.);
02300                         } else
02301                             break;
02302                     } else
02303                         break;
02304 
02305                     SbVec3f p1(pnt1.x,pnt1.y,zConstr);
02306                     SbVec3f p2(pnt2.x,pnt2.y,zConstr);
02307 
02308                     SbVec3f dir = (p2-p1);
02309                     dir.normalize();
02310                     SbVec3f norm (-dir[1],dir[0],0);
02311 
02312                     float length = Constr->LabelDistance;
02313                     SbVec3f pos = p2 + length*dir;
02314 
02315                     SoDatumLabel *asciiText = dynamic_cast<SoDatumLabel *>(sep->getChild(4));
02316                     asciiText->string = SbString().sprintf("%.2f",Constr->Value);
02317 
02318                     // Get Bounding box dimensions for Datum text
02319                     Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView();
02320                     Gui::View3DInventorViewer *viewer = static_cast<Gui::View3DInventor *>(mdi)->getViewer();
02321 
02322                     // [FIX ME] Its an attempt to find the height of the text using the bounding box, but is in correct.
02323                     SoGetBoundingBoxAction bbAction(viewer->getViewportRegion());
02324                     bbAction.apply(sep->getChild(3));
02325 
02326                     float bx=0,by=0,bz=0;
02327                     SbBox3f bbox = bbAction.getBoundingBox();
02328                     if (!bbox.isEmpty())
02329                         bbox.getSize(bx,by,bz);
02330                     SbVec3f textBB(bx,by,bz);
02331 
02332                     SbVec3f textBBCenter = bbAction.getBoundingBox().getCenter();
02333 
02334                     // Get magnitude of angle between horizontal
02335                     double angle = atan2f(dir[1],dir[0]);
02336                     bool flip=false;
02337                     if (angle > M_PI_2+M_PI/12) {
02338                         angle -= M_PI;
02339                         flip = true;
02340                     } else if (angle <= -M_PI_2+M_PI/12) {
02341                         angle += M_PI;
02342                         flip = true;
02343                     }
02344 
02345                     SbVec3f textpos = pos + norm * ( (flip ? 1:-1) * textBBCenter[1] / 1.7f);
02346 
02347                     // set position and rotation of Datums Text
02348                     SoTransform *transform = dynamic_cast<SoTransform *>(sep->getChild(2));
02349                     transform->rotation.setValue(SbVec3f(0, 0, 1), (float)angle);
02350                     transform->translation.setValue(textpos);
02351 
02352                     // Get the datum nodes
02353                     SoSeparator *sepDatum = dynamic_cast<SoSeparator *>(sep->getChild(1));
02354                     SoCoordinate3 *datumCord = dynamic_cast<SoCoordinate3 *>(sepDatum->getChild(0));
02355 
02356                     SbVec3f p3 = pos + dir * (6+textBB[0]/1.7f);
02357                     if ((p3-p1).length() > (p2-p1).length())
02358                         p2 = p3;
02359 
02360                     // Calculate the coordinates for the parallel datum lines
02361                     datumCord->point.set1Value(0,p1);
02362                     datumCord->point.set1Value(1,pos - dir * (1+textBB[0]/1.7f) );
02363                     datumCord->point.set1Value(2,pos + dir * (1+textBB[0]/1.7f) );
02364                     datumCord->point.set1Value(3,p2);
02365 
02366                     // Use the coordinates calculated earlier to the lineset
02367                     SoLineSet *datumLineSet = dynamic_cast<SoLineSet *>(sepDatum->getChild(1));
02368                     datumLineSet->numVertices.set1Value(0,2);
02369                     datumLineSet->numVertices.set1Value(1,2);
02370                 }
02371                 break;
02372             case Coincident: // nothing to do for coincident
02373             case None:
02374                 break;
02375         }
02376     }
02377 
02378     this->drawConstraintIcons();
02379     this->updateColor();
02380 
02381     // delete the cloned objects
02382     for (std::vector<Part::Geometry *>::iterator it = tempGeo.begin(); it != tempGeo.end(); ++it)
02383         if (*it) delete *it;
02384 
02385     if (mdi && mdi->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) {
02386         static_cast<Gui::View3DInventor *>(mdi)->getViewer()->render();
02387     }
02388 }
02389 
02390 void ViewProviderSketch::rebuildConstraintsVisual(void)
02391 {
02392     const std::vector<Sketcher::Constraint *> &ConStr = getSketchObject()->Constraints.getValues();
02393     // clean up
02394     edit->constrGroup->removeAllChildren();
02395     edit->vConstrType.clear();
02396 
02397     for (std::vector<Sketcher::Constraint *>::const_iterator it = ConStr.begin(); it != ConStr.end(); ++it) {
02398         // root separator for one constraint
02399         SoSeparator *sep = new SoSeparator();
02400         // no caching for fluctuand data structures
02401         sep->renderCaching = SoSeparator::OFF;
02402         // every constrained visual node gets its own material for preselection and selection
02403         SoMaterial *Material = new SoMaterial;
02404         Material->diffuseColor = ConstrDimColor;
02405         sep->addChild(Material);
02406 
02407         // distinguish different constraint types to build up
02408         switch ((*it)->Type) {
02409             case Distance:
02410             case DistanceX:
02411             case DistanceY:
02412             case Radius:
02413             case Angle:
02414                 {
02415                     SoSeparator *sepDatum = new SoSeparator();
02416                     sepDatum->addChild(new SoCoordinate3());
02417                     SoLineSet *lineSet = new SoLineSet;
02418                     sepDatum->addChild(lineSet);
02419 
02420                     sep->addChild(sepDatum);
02421 
02422                     // Add the datum text
02423                     sep->addChild(new SoTransform());
02424 
02425                     // add font for the datum text
02426                     SoFont *font = new SoFont();
02427                     font->size = 8.f;
02428                     font->name = "FreeSans:bold, Helvetica, Arial, FreeSans:bold";
02429 
02430                     sep->addChild(font);
02431 
02432                     SoDatumLabel *text = new SoDatumLabel();
02433                     //text->justification =  SoDatumLabel::CENTER;
02434                     text->string = "";
02435                     text->textColor = ConstrDimColor;
02436                     sep->addChild(text);
02437 
02438                     edit->vConstrType.push_back((*it)->Type);
02439                 }
02440                 break;
02441             case Horizontal:
02442             case Vertical:
02443                 {
02444                     sep->addChild(new SoZoomTranslation()); // 1.
02445                     sep->addChild(new SoImage());       // 2. constraint icon
02446 
02447                     // remember the type of this constraint node
02448                     edit->vConstrType.push_back((*it)->Type);
02449                 }
02450                 break;
02451             case Coincident: // no visual for coincident so far
02452                 edit->vConstrType.push_back(Coincident);
02453                 break;
02454             case Parallel:
02455             case Perpendicular:
02456             case Equal:
02457                 {
02458                     // Add new nodes to Constraint Seperator
02459                     sep->addChild(new SoZoomTranslation()); // 1.
02460                     sep->addChild(new SoImage());           // 2. first constraint icon
02461                     sep->addChild(new SoZoomTranslation()); // 3.
02462                     sep->addChild(new SoImage());           // 4. second constraint icon
02463 
02464                     // remember the type of this constraint node
02465                     edit->vConstrType.push_back((*it)->Type);
02466                 }
02467                 break;
02468             case PointOnObject:
02469             case Tangent:
02470                 {
02471                     // Add new nodes to Constraint Seperator
02472                     sep->addChild(new SoZoomTranslation()); // 1.
02473                     sep->addChild(new SoImage());           // 2. constraint icon
02474 
02475                     if ((*it)->Type == Tangent) {
02476                         Part::Geometry *geo1 = getSketchObject()->Geometry.getValues()[(*it)->First];
02477                         Part::Geometry *geo2 = getSketchObject()->Geometry.getValues()[(*it)->Second];
02478                         if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() &&
02479                             geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
02480                             sep->addChild(new SoZoomTranslation());
02481                             sep->addChild(new SoImage());   // 3. second constraint icon
02482                         }
02483                     }
02484 
02485                     edit->vConstrType.push_back((*it)->Type);
02486                 }
02487                 break;
02488             case Symmetric:
02489                 {
02490                     SoSeparator *sepArrows = new SoSeparator();
02491                     sepArrows->addChild(new SoCoordinate3());
02492                     SoLineSet *lineSet = new SoLineSet;
02493                     sepArrows->addChild(lineSet);
02494                     sep->addChild(sepArrows);           // 1.
02495 
02496                     // Add new nodes to Constraint Seperator
02497                     sep->addChild(new SoTranslation()); // 2.
02498                     sep->addChild(new SoImage());       // 3. constraint icon
02499 
02500                     edit->vConstrType.push_back((*it)->Type);
02501                 }
02502                 break;
02503             default:
02504                 edit->vConstrType.push_back(None);
02505             }
02506 
02507         edit->constrGroup->addChild(sep);
02508     }
02509 }
02510 
02511 void ViewProviderSketch::drawEdit(const std::vector<Base::Vector2D> &EditCurve)
02512 {
02513     assert(edit);
02514 
02515     edit->EditCurveSet->numVertices.setNum(1);
02516     edit->EditCurvesCoordinate->point.setNum(EditCurve.size());
02517     SbVec3f *verts = edit->EditCurvesCoordinate->point.startEditing();
02518     int32_t *index = edit->EditCurveSet->numVertices.startEditing();
02519 
02520     int i=0; // setting up the line set
02521     for (std::vector<Base::Vector2D>::const_iterator it = EditCurve.begin(); it != EditCurve.end(); ++it,i++)
02522         verts[i].setValue(it->fX,it->fY,zEdit);
02523 
02524     index[0] = EditCurve.size();
02525     edit->EditCurvesCoordinate->point.finishEditing();
02526     edit->EditCurveSet->numVertices.finishEditing();
02527 }
02528 
02529 void ViewProviderSketch::updateData(const App::Property *prop)
02530 {
02531     ViewProvider2DObject::updateData(prop);
02532 
02533     if (edit && (prop == &(getSketchObject()->Geometry) || &(getSketchObject()->Constraints))) {
02534         edit->FullyConstrained = false;
02535         int dofs = edit->ActSketch.setUpSketch(getSketchObject()->Geometry.getValues(),
02536                                                getSketchObject()->Constraints.getValues());
02537         std::string msg;
02538         if (getSketchObject()->Geometry.getSize() == 0) {
02539             signalSetUp(-1, 0, msg);
02540             signalSolved(-1, 0);
02541         }
02542         else if (dofs < 0) { // over-constrained sketch
02543             SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
02544             //Base::Console().Warning("Over-constrained sketch\n%s",msg.c_str());
02545             signalSetUp(3, 0, msg);
02546             signalSolved(-1,0);
02547         }
02548         else if (edit->ActSketch.hasConflicts()) { // conflicting constraints
02549             SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
02550             //Base::Console().Warning("Sketch with conflicting constraints\n%s",msg.c_str());
02551             signalSetUp(2, dofs, msg);
02552             signalSolved(-1,0);
02553         }
02554         else if (edit->ActSketch.solve() == 0) { // solving the sketch
02555             if (dofs == 0) {
02556                 // color the sketch as fully constrained
02557                 edit->FullyConstrained = true;
02558                 //Base::Console().Message("Fully constrained sketch\n");
02559                 signalSetUp(0, 0, msg);
02560             }
02561             else {
02562                 //Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs);
02563                 signalSetUp(1, dofs, msg);
02564             }
02565             signalSolved(0,edit->ActSketch.SolveTime);
02566         }
02567         else {
02568             signalSolved(1,edit->ActSketch.SolveTime);
02569         }
02570         draw(true);
02571     }
02572     if (edit && &(getSketchObject()->Constraints)) {
02573         // send the signal for the TaskDlg.
02574         signalConstraintsChanged();
02575     }
02576 }
02577 
02578 void ViewProviderSketch::onChanged(const App::Property *prop)
02579 {
02580     // call father
02581     PartGui::ViewProvider2DObject::onChanged(prop);
02582 }
02583 
02584 void ViewProviderSketch::attach(App::DocumentObject *pcFeat)
02585 {
02586     ViewProviderPart::attach(pcFeat);
02587 }
02588 
02589 void ViewProviderSketch::setupContextMenu(QMenu *menu, QObject *receiver, const char *member)
02590 {
02591     menu->addAction(QObject::tr("Edit sketch"), receiver, member);
02592 }
02593 
02594 bool ViewProviderSketch::setEdit(int ModNum)
02595 {
02596     // When double-clicking on the item for this sketch the
02597     // object unsets and sets its edit mode without closing
02598     // the task panel
02599     Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog();
02600     TaskDlgEditSketch *sketchDlg = qobject_cast<TaskDlgEditSketch *>(dlg);
02601     if (sketchDlg && sketchDlg->getSketchView() != this)
02602         sketchDlg = 0; // another sketch left open its task panel
02603     if (dlg && !sketchDlg) {
02604         QMessageBox msgBox;
02605         msgBox.setText(QObject::tr("A dialog is already open in the task panel"));
02606         msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?"));
02607         msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
02608         msgBox.setDefaultButton(QMessageBox::Yes);
02609         int ret = msgBox.exec();
02610         if (ret == QMessageBox::Yes)
02611             Gui::Control().closeDialog();
02612         else
02613             return false;
02614     }
02615 
02616     // clear the selection (convenience)
02617     Gui::Selection().clearSelection();
02618 
02619     // create the container for the addtitional edit data
02620     assert(!edit);
02621     edit = new EditData();
02622 
02623     createEditInventorNodes();
02624     this->hide(); // avoid that the wires interfere with the edit lines
02625 
02626     ShowGrid.setValue(true);
02627     TightGrid.setValue(false);
02628 
02629     ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
02630     float transparency;
02631 
02632     // set the point color
02633     unsigned long color = (unsigned long)(VertexColor.getPackedValue());
02634     color = hGrp->GetUnsigned("EditedVertexColor", color);
02635     VertexColor.setPackedValue((uint32_t)color, transparency);
02636     // set the curve color
02637     color = (unsigned long)(CurveColor.getPackedValue());
02638     color = hGrp->GetUnsigned("EditedEdgeColor", color);
02639     CurveColor.setPackedValue((uint32_t)color, transparency);
02640     // set the construction curve color
02641     color = (unsigned long)(CurveDraftColor.getPackedValue());
02642     color = hGrp->GetUnsigned("ConstructionColor", color);
02643     CurveDraftColor.setPackedValue((uint32_t)color, transparency);
02644     // set the cross lines color
02645     //CrossColorV.setPackedValue((uint32_t)color, transparency);
02646     //CrossColorH.setPackedValue((uint32_t)color, transparency);
02647     // set the fully constrained color
02648     color = (unsigned long)(FullyConstrainedColor.getPackedValue());
02649     color = hGrp->GetUnsigned("FullyConstrainedColor", color);
02650     FullyConstrainedColor.setPackedValue((uint32_t)color, transparency);
02651     // constraints dimensions and icons colors are hard coded
02652     // ConstrDimColor;
02653     // ConstrIcoColor;
02654 
02655     // set the highlight color
02656     unsigned long highlight = (unsigned long)(PreselectColor.getPackedValue());
02657     highlight = hGrp->GetUnsigned("HighlightColor", highlight);
02658     PreselectColor.setPackedValue((uint32_t)highlight, transparency);
02659     // set the selection color
02660     highlight = (unsigned long)(SelectColor.getPackedValue());
02661     highlight = hGrp->GetUnsigned("SelectionColor", highlight);
02662     SelectColor.setPackedValue((uint32_t)highlight, transparency);
02663 
02664     // start the edit dialog
02665     if (sketchDlg)
02666         Gui::Control().showDialog(sketchDlg);
02667     else
02668         Gui::Control().showDialog(new TaskDlgEditSketch(this));
02669 
02670     // set up the sketch and diagnose possible conflicts
02671     int dofs = edit->ActSketch.setUpSketch(getSketchObject()->Geometry.getValues(),
02672                                            getSketchObject()->Constraints.getValues());
02673     std::string msg;
02674     if (getSketchObject()->Geometry.getSize() == 0) {
02675         signalSetUp(-1, 0, msg);
02676         signalSolved(-1, 0);
02677     }
02678     else if (dofs < 0) { // over-constrained sketch
02679         SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
02680         //Base::Console().Warning("Over-constrained sketch\n%s",msg.c_str());
02681         signalSetUp(3, 0, msg);
02682         signalSolved(-1, 0);
02683     }
02684     else if (edit->ActSketch.hasConflicts()) { // conflicting constraints
02685         SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg);
02686         //Base::Console().Warning("Sketch with conflicting constraints\n%s",msg.c_str());
02687         signalSetUp(2, dofs, msg);
02688         signalSolved(-1, 0);
02689     }
02690     else if (edit->ActSketch.solve() == 0) { // solving the sketch
02691         if (dofs == 0) {
02692             // color the sketch as fully constrained
02693             edit->FullyConstrained = true;
02694             //Base::Console().Message("Fully constrained sketch\n");
02695             signalSetUp(0, 0, msg);
02696         }
02697         else {
02698             //Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs);
02699             signalSetUp(1, dofs, msg);
02700         }
02701         signalSolved(0, edit->ActSketch.SolveTime);
02702     }
02703     else {
02704         signalSolved(1, edit->ActSketch.SolveTime);
02705     }
02706 
02707     draw();
02708 
02709     return true;
02710 }
02711 
02712 void ViewProviderSketch::createEditInventorNodes(void)
02713 {
02714     assert(edit);
02715 
02716     edit->EditRoot = new SoSeparator;
02717     pcRoot->addChild(edit->EditRoot);
02718     edit->EditRoot->renderCaching = SoSeparator::OFF ;
02719 
02720     // stuff for the points ++++++++++++++++++++++++++++++++++++++
02721     edit->PointsMaterials = new SoMaterial;
02722     edit->EditRoot->addChild(edit->PointsMaterials);
02723 
02724     SoMaterialBinding *MtlBind = new SoMaterialBinding;
02725     MtlBind->value = SoMaterialBinding::PER_VERTEX;
02726     edit->EditRoot->addChild(MtlBind);
02727 
02728     edit->PointsCoordinate = new SoCoordinate3;
02729     edit->EditRoot->addChild(edit->PointsCoordinate);
02730 
02731     SoDrawStyle *DrawStyle = new SoDrawStyle;
02732     DrawStyle->pointSize = 8;
02733     edit->EditRoot->addChild(DrawStyle);
02734     edit->PointSet = new SoMarkerSet;
02735     edit->PointSet->markerIndex = SoMarkerSet::CIRCLE_FILLED_7_7;
02736     edit->EditRoot->addChild(edit->PointSet);
02737 
02738     // stuff for the Curves +++++++++++++++++++++++++++++++++++++++
02739     edit->CurvesMaterials = new SoMaterial;
02740     edit->EditRoot->addChild(edit->CurvesMaterials);
02741 
02742     MtlBind = new SoMaterialBinding;
02743     MtlBind->value = SoMaterialBinding::PER_FACE;
02744     edit->EditRoot->addChild(MtlBind);
02745 
02746     edit->CurvesCoordinate = new SoCoordinate3;
02747     edit->EditRoot->addChild(edit->CurvesCoordinate);
02748 
02749     DrawStyle = new SoDrawStyle;
02750     DrawStyle->lineWidth = 3;
02751     edit->EditRoot->addChild(DrawStyle);
02752 
02753     edit->CurveSet = new SoLineSet;
02754 
02755     edit->EditRoot->addChild(edit->CurveSet);
02756 
02757     // stuff for the RootCross lines +++++++++++++++++++++++++++++++++++++++
02758     MtlBind = new SoMaterialBinding;
02759     MtlBind->value = SoMaterialBinding::PER_FACE;
02760     edit->EditRoot->addChild(MtlBind);
02761 
02762     DrawStyle = new SoDrawStyle;
02763     DrawStyle->lineWidth = 2;
02764     edit->EditRoot->addChild(DrawStyle);
02765 
02766     edit->RootCrossMaterialsV = new SoMaterial;
02767     edit->RootCrossMaterialsV->diffuseColor.set1Value(0,CrossColorV);
02768     edit->EditRoot->addChild(edit->RootCrossMaterialsV);
02769 
02770     edit->RootCrossCoordinateV = new SoCoordinate3;
02771     edit->EditRoot->addChild(edit->RootCrossCoordinateV);
02772 
02773     edit->RootCrossSetV = new SoLineSet;
02774     edit->RootCrossSetV->numVertices.set1Value(0,2);
02775     edit->EditRoot->addChild(edit->RootCrossSetV);
02776 
02777     edit->RootCrossMaterialsH = new SoMaterial;
02778     edit->RootCrossMaterialsH->diffuseColor.set1Value(0,CrossColorH);
02779     edit->EditRoot->addChild(edit->RootCrossMaterialsH);
02780 
02781     edit->RootCrossCoordinateH = new SoCoordinate3;
02782     edit->EditRoot->addChild(edit->RootCrossCoordinateH);
02783 
02784     edit->RootCrossSetH = new SoLineSet;
02785     edit->RootCrossSetH->numVertices.set1Value(0,2);
02786     edit->EditRoot->addChild(edit->RootCrossSetH);
02787 
02788 
02789     // stuff for the EditCurves +++++++++++++++++++++++++++++++++++++++
02790     edit->EditCurvesMaterials = new SoMaterial;
02791     edit->EditRoot->addChild(edit->EditCurvesMaterials);
02792 
02793     edit->EditCurvesCoordinate = new SoCoordinate3;
02794     edit->EditRoot->addChild(edit->EditCurvesCoordinate);
02795 
02796     DrawStyle = new SoDrawStyle;
02797     DrawStyle->lineWidth = 3;
02798     edit->EditRoot->addChild(DrawStyle);
02799 
02800     edit->EditCurveSet = new SoLineSet;
02801     edit->EditRoot->addChild(edit->EditCurveSet);
02802 
02803     // stuff for the edit coordinates ++++++++++++++++++++++++++++++++++++++
02804     SoMaterial *EditMaterials = new SoMaterial;
02805     EditMaterials->diffuseColor = SbColor(0,0,1);
02806     edit->EditRoot->addChild(EditMaterials);
02807 
02808     SoSeparator *Coordsep = new SoSeparator();
02809     // no caching for fluctuand data structures
02810     Coordsep->renderCaching = SoSeparator::OFF;
02811 
02812     SoFont *font = new SoFont();
02813     font->size = 15.0;
02814     Coordsep->addChild(font);
02815 
02816     edit->textPos = new SoTranslation();
02817     Coordsep->addChild(edit->textPos);
02818 
02819     edit->textX = new SoText2();
02820     edit->textX->justification = SoText2::LEFT;
02821     edit->textX->string = "";
02822     Coordsep->addChild(edit->textX);
02823     edit->EditRoot->addChild(Coordsep);
02824 
02825     // group node for the Constraint visual +++++++++++++++++++++++++++++++++++
02826     MtlBind = new SoMaterialBinding;
02827     MtlBind->value = SoMaterialBinding::OVERALL ;
02828     edit->EditRoot->addChild(MtlBind);
02829 
02830     // add font for the text shown constraints
02831     font = new SoFont();
02832     font->size = 8.0;
02833     edit->EditRoot->addChild(font);
02834 
02835     // use small line width for the Constraints
02836     DrawStyle = new SoDrawStyle;
02837     DrawStyle->lineWidth = 1;
02838     edit->EditRoot->addChild(DrawStyle);
02839 
02840     // add the group where all the constraints has its SoSeparator
02841     edit->constrGroup = new SoGroup();
02842     edit->EditRoot->addChild(edit->constrGroup);
02843 }
02844 
02845 void ViewProviderSketch::unsetEdit(int ModNum)
02846 {
02847     ShowGrid.setValue(false);
02848     TightGrid.setValue(true);
02849 
02850     edit->EditRoot->removeAllChildren();
02851     pcRoot->removeChild(edit->EditRoot);
02852 
02853     if (edit->sketchHandler) {
02854         edit->sketchHandler->unsetCursor();
02855         purgeHandler();
02856     }
02857     delete edit;
02858     edit = 0;
02859 
02860     this->show();
02861 
02862     // and update the sketch
02863     getSketchObject()->getDocument()->recompute();
02864 
02865     // clear the selection and set the new/edited sketch(convenience)
02866     Gui::Selection().clearSelection();
02867     std::string ObjName = getSketchObject()->getNameInDocument();
02868     std::string DocName = getSketchObject()->getDocument()->getName();
02869     Gui::Selection().addSelection(DocName.c_str(),ObjName.c_str());
02870 
02871     // when pressing ESC make sure to close the dialog
02872     Gui::Control().closeDialog();
02873 }
02874 
02875 void ViewProviderSketch::setEditViewer(Gui::View3DInventorViewer* viewer, int ModNum)
02876 {
02877     Base::Placement plm = getSketchObject()->Placement.getValue();
02878     Base::Rotation tmp(plm.getRotation());
02879 
02880     SbRotation rot((float)tmp[0],(float)tmp[1],(float)tmp[2],(float)tmp[3]);
02881     viewer->setCameraOrientation(rot);
02882 
02883     viewer->setEditing(TRUE);
02884     SoNode* root = viewer->getSceneGraph();
02885     static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(FALSE);
02886 }
02887 
02888 void ViewProviderSketch::unsetEditViewer(Gui::View3DInventorViewer* viewer)
02889 {
02890     viewer->setEditing(FALSE);
02891     SoNode* root = viewer->getSceneGraph();
02892     static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(TRUE);
02893 }
02894 
02895 void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos)
02896 {
02897     char buf[40];
02898     sprintf( buf, " (%.1f,%.1f)", Pos.fX,Pos.fY );
02899     edit->textX->string = buf;
02900     edit->textPos->translation = SbVec3f(Pos.fX,Pos.fY,zText);
02901 }
02902 
02903 void ViewProviderSketch::resetPositionText(void)
02904 {
02905     edit->textX->string = "";
02906 }
02907 
02908 void ViewProviderSketch::setPreselectPoint(int PreselectPoint)
02909 {
02910     if (edit) {
02911         SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
02912         float x,y,z;
02913         if (edit->PreselectPoint != -1 &&
02914             edit->SelPointSet.find(edit->PreselectPoint) == edit->SelPointSet.end()) {
02915             // send to background
02916             pverts[edit->PreselectPoint].getValue(x,y,z);
02917             pverts[edit->PreselectPoint].setValue(x,y,zPoints);
02918         }
02919         // bring to foreground
02920         pverts[PreselectPoint].getValue(x,y,z);
02921         pverts[PreselectPoint].setValue(x,y,zHighlight);
02922         edit->PreselectPoint = PreselectPoint;
02923         edit->PointsCoordinate->point.finishEditing();
02924     }
02925 }
02926 
02927 void ViewProviderSketch::resetPreselectPoint(void)
02928 {
02929     if (edit) {
02930         if (edit->PreselectPoint != -1 &&
02931             edit->SelPointSet.find(edit->PreselectPoint) == edit->SelPointSet.end()) {
02932             // send to background
02933             SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
02934             float x,y,z;
02935             pverts[edit->PreselectPoint].getValue(x,y,z);
02936             pverts[edit->PreselectPoint].setValue(x,y,zPoints);
02937             edit->PointsCoordinate->point.finishEditing();
02938         }
02939         edit->PreselectPoint = -1;
02940     }
02941 }
02942 
02943 void ViewProviderSketch::addSelectPoint(int SelectPoint)
02944 {
02945     if (edit) {
02946         SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
02947         // bring to foreground
02948         float x,y,z;
02949         pverts[SelectPoint].getValue(x,y,z);
02950         pverts[SelectPoint].setValue(x,y,zHighlight);
02951         edit->SelPointSet.insert(SelectPoint);
02952         edit->PointsCoordinate->point.finishEditing();
02953     }
02954 }
02955 
02956 void ViewProviderSketch::removeSelectPoint(int SelectPoint)
02957 {
02958     if (edit) {
02959         SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
02960         // send to background
02961         float x,y,z;
02962         pverts[SelectPoint].getValue(x,y,z);
02963         pverts[SelectPoint].setValue(x,y,zPoints);
02964         edit->SelPointSet.erase(SelectPoint);
02965         edit->PointsCoordinate->point.finishEditing();
02966     }
02967 }
02968 
02969 void ViewProviderSketch::clearSelectPoints(void)
02970 {
02971     if (edit) {
02972         SbVec3f *pverts = edit->PointsCoordinate->point.startEditing();
02973         // send to background
02974         float x,y,z;
02975         for (std::set<int>::const_iterator it=edit->SelPointSet.begin();
02976              it != edit->SelPointSet.end(); ++it) {
02977             pverts[*it].getValue(x,y,z);
02978             pverts[*it].setValue(x,y,zPoints);
02979         }
02980         edit->PointsCoordinate->point.finishEditing();
02981         edit->SelPointSet.clear();
02982     }
02983 }
02984 
02985 int ViewProviderSketch::getPreselectPoint(void) const
02986 {
02987     if (edit)
02988         return edit->PreselectPoint;
02989     return -1;
02990 }
02991 
02992 int ViewProviderSketch::getPreselectCurve(void) const
02993 {
02994     if (edit)
02995         return edit->PreselectCurve;
02996     return -1;
02997 }
02998 
02999 int ViewProviderSketch::getPreselectConstraint(void) const
03000 {
03001     if (edit)
03002         return edit->PreselectConstraint;
03003     return -1;
03004 }
03005 
03006 Sketcher::SketchObject *ViewProviderSketch::getSketchObject(void) const
03007 {
03008     return dynamic_cast<Sketcher::SketchObject *>(pcObject);
03009 }
03010 
03011 bool ViewProviderSketch::onDelete(const std::vector<std::string> &subList)
03012 {
03013     //FIXME use the selection subelements instead of the Sel Sets...
03014     if (edit) {
03015         // We must tmp. block the signaling because otherwise we empty the sets while
03016         // looping through them which may cause a crash
03017         this->blockConnection(true);
03018         std::set<int>::const_reverse_iterator rit;
03019         for (rit = edit->SelConstraintSet.rbegin(); rit != edit->SelConstraintSet.rend(); rit++) {
03020             try {
03021                 Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.delConstraint(%i)"
03022                                        ,getObject()->getNameInDocument(), *rit);
03023             }
03024             catch (const Base::Exception& e) {
03025                 Base::Console().Error("%s\n", e.what());
03026             }
03027         }
03028         for (rit = edit->SelCurvSet.rbegin(); rit != edit->SelCurvSet.rend(); rit++) {
03029             try {
03030                 Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.delGeometry(%i)"
03031                                        ,getObject()->getNameInDocument(), *rit);
03032             }
03033             catch (const Base::Exception& e) {
03034                 Base::Console().Error("%s\n", e.what());
03035             }
03036         }
03037         for (rit = edit->SelPointSet.rbegin(); rit != edit->SelPointSet.rend(); rit++) {
03038             try {
03039                 Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.delConstraintOnPoint(%i)"
03040                                        ,getObject()->getNameInDocument(), *rit);
03041             }
03042             catch (const Base::Exception& e) {
03043                 Base::Console().Error("%s\n", e.what());
03044             }
03045         }
03046 
03047         this->blockConnection(false);
03048         Gui::Selection().clearSelection();
03049         resetPreselectPoint();
03050         edit->PreselectCurve = -1;
03051         edit->PreselectCross = -1;
03052         edit->PreselectConstraint = -1;
03053         this->drawConstraintIcons();
03054         this->updateColor();
03055         // if in edit not delete the object
03056         return false;
03057     }
03058     // if not in edit delete the whole object
03059     return true;
03060 }

Generated on Wed Nov 23 19:01:01 2011 for FreeCAD by  doxygen 1.6.1