Sketcher: EditModeCoinManager/DrawSkechHandler refactoring

======================================================

Creation of EditModeCoinManager class and helpers.

In a nutshell:
- EditModeCoinManager gets most of the content of struct EditData
- Drawing is partly outsourced to EditModeCoinManager
- EditModeCoinManager gets a nested Observer class to deal with parameters
- A struct DrawingParameters is created to store all parameters used for drawing
- EditModeCoinManager assume responsibility for determining the drawing size of the Axes
- Preselection detection responsibility is moved to EditModeCoinManager.
- Generation of constraint nodes and constraint drawing is moved to EditModeCoinManager.
- Constraint generation parameters are refactored into ConstraintParameters.
- Text rendering functions are moved to EditModeCoinManager.
- Move HDPI resolution responsibility from VPSketch to EditModeCoinManager
- Move responsibility to create the scenograph for edit mode to EditModeCoinManager
- Move full updateColor responsibility to EditModeCoinManager
- Allows for mapping N logical layers (LayerId of GeometryFacade) to M coin Layers (M<N). This
is convenient as, unless the representation must be different, there is no point in creating coin
layers (overhead).

Refactoring of geometry drawing:
- Determination of the curve values to draw are outsourced to OCC (SRP and remove code duplications).
- Refactor specific drawing of each geometry type into a single template method, based on classes of geometry.
- Drawing of geometry and constraints made agnostic of scale factors of BSpline weights so that a uniform treatment can be provided.

Refactoring of Overlay Layer:
- A new class EditModeInformationOverlayConverter is a full rewrite of the previous overlay routines.

ViewProviderSketch:
- Major cleanup due to migration of functionalities to EditModeCoinManager
- Reduce public api of ViewProviderSketch due to refactor of DrawSketchHandler
- Major addition of documentation
- ShortcutListener implementation using new ViewProvider Attorney
- Gets a parameter handling nested class to handle all parameters (observer)
- Move rubberband to smart pointer
- Refactor selection and preselection into nested classes
- Removal of SEL_PARAMS macro. This macro was making the code unreadable as it "captured" a local stringstream that appeared unused. Substituted by local private member functions.
- Remove EditData
- Improve documentation
- Refactor Preselection struct to remove magical numbers
- Refactor Selection mechanism to remove hacks

ViewProviderSketchDrawSketchHandlerAttorney:
- new Attorney to limit access to ViewProviderSketch and reduce its public interface
- In order to enforce a certain degree of encapsulation and promote a not too tight coupling, while still allowing well
defined collaboration, DrawSketchHandler accesses ViewProviderSketch via this Attorney class.
-DrawSketchHandler has the responsibility of drawing edit temporal curves and markers necessary to enable visual feedback
to the user, as well as the UI interaction during such edits. This is its exclusive responsibility under the Single
Responsibility Principle.
- A plethora of speciliased handlers derive from DrawSketchHandler for each specialised editing (see for example all the
handlers for creation of new geometry). These derived classes do * not * have direct access to the
ViewProviderSketchDrawSketchHandlerAttorney. This is intentional to keep coupling under control. However, generic
functionality requiring access to the Attorney can be implemented in DrawSketchHandler and used from its derived classes
by virtue of the inheritance. This promotes a concentrating the coupling in a single point (and code reuse).

EditModeCoinManager:
- Refactor of updateConstraintColor
- Multifield - new struct to identify a single element in a multifield field per layer
- Move geometry management to delegate class EditModeCoinGeometryManager
- Remove refactored code that was never used in the original ViewProviderSketch.

CommandSketcherBSpline:
- EditModeCoinManager automatically tracks parameter change and triggers the necessary redraw, rendering an explicit redraw obsolete and unnecessary.

Rebase on top of master:
- Commits added to master to ViewProviderSketch applied to EditModeCoinManager.
- Memory leaks - wmayer
- Constraint Diameter Symbol - OpenBrain
- Minor bugfix to display angle constraints - syres

Architecture Description
=======================

* Encapsulation and collaboration - restricting friendship - reducing public interface

Summary:
- DrawSketchHandler to ViewProviderSketch friendship regulated via attorney.
- ShortcutListener to ViewProviderSketch friendship regulated via attorney.
- EditModeCoinManager (new class) to ViewProviderSketch friendship regulated via attorney.
- ViewProviderSketch public interface is heavily reduced.

In further detail:
While access from ViewProviderSketch to other classes is regulated via their public interface, DrawSketchHandler, ShortcutListener and EditCoinManager (new class) access
to ViewProviderSketch non-public interface via attorneys. Previously, it was an unrestricted access (friend classes). Now this interface is restricted and regulated via attorneys.
This increases the encapsulation of ViewProviderSketch, reduces the coupling between classes and promotes an ordered growth. This I call the "collaboration interface".

At the same time, ViewProviderSketch substantially reduces its public interface. Access from Command draw handlers (deriving from DrawSketchHandler) is intended to be restricted to
the functionality exposed by DrawSketchHandler to its derived classes. However, this is still only partly enforced to keep the refactoring within limits. A further refactoring of
DrawSketchHandler and derivatives is for future discussion.

* Complexity and delegation

Summary:
- Complexity of coin node management is dealt with by delegation to helper classes and specialised objects.

In further detail:

ViewProviderSketch is halved in terms of code size. Higher level ViewProviderSketch functions remain

* Automatic update of parameters - Parameter observer nested classes

Summary:
- ViewProviderSketch and CoinManager get their own observer nested classes to monitor the parameters relevant to them and automatically update on change.

The split enables that each class deals only with parameters within their own responsibilities, effectively isolating the specifics and decoupling the implementations. It is
more convenient as there is no need to leave edit mode to update parameters. It is more compact as it leverages core code.

More information:
https://forum.freecadweb.org/viewtopic.php?p=553257#p553257
This commit is contained in:
Abdullah Tahiri
2021-12-07 14:17:46 +01:00
committed by abdullahtahiriyo
parent 2f77d3bc95
commit 71c9dc3e0e
25 changed files with 8048 additions and 5005 deletions

View File

@@ -0,0 +1,829 @@
/***************************************************************************
* Copyright (c) 2021 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoGroup.h>
# include <Inventor/nodes/SoSwitch.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoLineSet.h>
# include <Inventor/nodes/SoFont.h>
# include <Inventor/nodes/SoMarkerSet.h>
# include <Inventor/nodes/SoTranslation.h>
# include <Inventor/nodes/SoText2.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/SoPickedPoint.h>
# include <Inventor/details/SoPointDetail.h>
# include <Inventor/details/SoDetail.h>
# include <Inventor/details/SoLineDetail.h>
# include <Inventor/nodes/SoAnnotation.h>
# include <Inventor/nodes/SoImage.h>
# include <Inventor/nodes/SoInfo.h>
# include <Inventor/actions/SoRayPickAction.h>
# include <Inventor/SbVec3f.h>
# include <Inventor/SbImage.h>
# include <memory>
#endif // #ifndef _PreComp_
#include <Gui/Inventor/SmSwitchboard.h>
#include <Mod/Part/App/Geometry.h>
#include <Mod/Sketcher/App/GeometryFacade.h>
#include <Mod/Sketcher/App/SolverGeometryExtension.h>
#include <Mod/Sketcher/App/GeoEnum.h>
#include <Mod/Sketcher/App/Constraint.h>
#include <Mod/Sketcher/App/GeoList.h>
#include <Base/Exception.h>
#include <Base/Tools2D.h>
#include <Base/UnitsApi.h>
#include <Gui/Utilities.h>
#include <Base/Converter.h>
#include <Base/Tools.h>
#include <Base/Vector3D.h>
#include <App/ObjectIdentifier.h>
#include <Gui/SoFCBoundingBox.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Inventor/MarkerBitmaps.h>
#include <Gui/Tools.h>
#include <qpainter.h>
#include "SoZoomTranslation.h"
#include "SoDatumLabel.h"
#include "EditModeInformationOverlayCoinConverter.h"
#include "EditModeGeometryCoinConverter.h"
#include "ViewProviderSketch.h"
#include "ViewProviderSketchCoinAttorney.h"
#include "EditModeGeometryCoinManager.h"
#include "EditModeConstraintCoinManager.h"
#include "EditModeCoinManager.h"
using namespace SketcherGui;
using namespace Sketcher;
//**************************** ParameterObserver nested class ******************************
EditModeCoinManager::ParameterObserver::ParameterObserver(EditModeCoinManager &client): Client(client)
{
initParameters();
subscribeToParameters();
}
EditModeCoinManager::ParameterObserver::~ParameterObserver()
{
unsubscribeToParameters();
}
void EditModeCoinManager::ParameterObserver::initParameters()
{
// static map to avoid substantial if/else branching
//
// key->first => String of parameter,
// key->second => Update function to be called for the parameter,
str2updatefunction = {
{"SegmentsPerGeometry",
[this](const std::string & param){updateCurvedEdgeCountSegmentsParameter(param);}},
{"BSplineDegreeVisible",
[this](const std::string & param){updateOverlayVisibilityParameter<OverlayVisibilityParameter::BSplineDegree>(param);}},
{"BSplineControlPolygonVisible",
[this](const std::string & param){updateOverlayVisibilityParameter<OverlayVisibilityParameter::BSplineControlPolygonVisible>(param);}},
{"BSplineCombVisible",
[this](const std::string & param){updateOverlayVisibilityParameter<OverlayVisibilityParameter::BSplineCombVisible>(param);}},
{"BSplineKnotMultiplicityVisible",
[this](const std::string & param){updateOverlayVisibilityParameter<OverlayVisibilityParameter::BSplineKnotMultiplicityVisible>(param);}},
{"BSplinePoleWeightVisible",
[this](const std::string & param){updateOverlayVisibilityParameter<OverlayVisibilityParameter::BSplinePoleWeightVisible>(param);}},
{"TopRenderGeometryId",
[this](const std::string & param){updateLineRenderingOrderParameters(param);}},
{"MidRenderGeometryId",
[this](const std::string & param){updateLineRenderingOrderParameters(param);}},
{"HideUnits",
[this](const std::string & param){updateConstraintPresentationParameters(param);}},
{"ShowDimensionalName",
[this](const std::string & param){updateConstraintPresentationParameters(param);}},
{"DimensionalStringFormat",
[this](const std::string & param){updateConstraintPresentationParameters(param);}},
{"ViewScalingFactor",
[this](const std::string & param){updateElementSizeParameters(param);}},
{"MarkerSize",
[this](const std::string & param){updateElementSizeParameters(param);}},
{"EditSketcherFontSize",
[this](const std::string & param){updateElementSizeParameters(param);}},
{"CreateLineColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.CreateCurveColor, param);}},
{"EditedVertexColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.VertexColor, param);}},
{"EditedEdgeColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.CurveColor, param);}},
{"ConstructionColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.CurveDraftColor, param);}},
{"InternalAlignedGeoColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.InternalAlignedGeoColor, param);}},
{"FullyConstraintElementColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.FullyConstraintElementColor, param);}},
{"FullyConstraintConstructionElementColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.FullyConstraintConstructionElementColor, param);}},
{"FullyConstraintInternalAlignmentColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.FullyConstraintInternalAlignmentColor, param);}},
{"FullyConstraintConstructionPointColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.FullyConstraintConstructionPointColor, param);}},
{"FullyConstraintElementColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.FullyConstraintElementColor, param);}},
{"InvalidSketchColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.InvalidSketchColor, param);}},
{"FullyConstrainedColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.FullyConstrainedColor, param);}},
{"ConstrainedDimColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.ConstrDimColor, param);}},
{"ConstrainedIcoColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.ConstrIcoColor, param);}},
{"NonDrivingConstrDimColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.NonDrivingConstrDimColor, param);}},
{"ExprBasedConstrDimColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.ExprBasedConstrDimColor, param);}},
{"DeactivatedConstrDimColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.DeactivatedConstrDimColor, param);}},
{"ExternalColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.CurveExternalColor, param);}},
{"HighlightColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.PreselectColor, param);}},
{"SelectionColor",
[this, drawingParameters = Client.drawingParameters](const std::string & param){updateColor(drawingParameters.SelectColor, param);}},
};
for( auto & val : str2updatefunction){
auto string = val.first;
auto function = val.second;
function(string);
}
}
void EditModeCoinManager::ParameterObserver::updateCurvedEdgeCountSegmentsParameter(const std::string & parametername)
{
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
int stdcountsegments = hGrp->GetInt(parametername.c_str(), 50);
// value cannot be smaller than 6
if (stdcountsegments < 6)
stdcountsegments = 6;
Client.drawingParameters.curvedEdgeCountSegments = stdcountsegments;
}
void EditModeCoinManager::ParameterObserver::updateLineRenderingOrderParameters(const std::string & parametername)
{
(void) parametername;
ParameterGrp::handle hGrpp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
Client.drawingParameters.topRenderingGeometry = DrawingParameters::GeometryRendering (hGrpp->GetInt("TopRenderGeometryId",1));
Client.drawingParameters.midRenderingGeometry = DrawingParameters::GeometryRendering (hGrpp->GetInt("MidRenderGeometryId",2));
}
void EditModeCoinManager::ParameterObserver::updateConstraintPresentationParameters(const std::string & parametername)
{
(void) parametername;
ParameterGrp::handle hGrpskg = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
Client.constraintParameters.bHideUnits = hGrpskg->GetBool("HideUnits", false);
Client.constraintParameters.bShowDimensionalName = hGrpskg->GetBool("ShowDimensionalName", false);
Client.constraintParameters.sDimensionalStringFormat = QString::fromStdString(hGrpskg->GetASCII("DimensionalStringFormat", "%N = %V"));
}
template<EditModeCoinManager::ParameterObserver::OverlayVisibilityParameter visibilityparameter>
void EditModeCoinManager::ParameterObserver::updateOverlayVisibilityParameter(const std::string & parametername)
{
ParameterGrp::handle hGrpsk = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
if constexpr (visibilityparameter == OverlayVisibilityParameter::BSplineDegree)
Client.overlayParameters.bSplineDegreeVisible = hGrpsk->GetBool(parametername.c_str(), true);
else if constexpr (visibilityparameter == OverlayVisibilityParameter::BSplineControlPolygonVisible)
Client.overlayParameters.bSplineControlPolygonVisible = hGrpsk->GetBool(parametername.c_str(), true);
else if constexpr (visibilityparameter == OverlayVisibilityParameter::BSplineCombVisible)
Client.overlayParameters.bSplineCombVisible = hGrpsk->GetBool(parametername.c_str(), true);
else if constexpr (visibilityparameter == OverlayVisibilityParameter::BSplineKnotMultiplicityVisible)
Client.overlayParameters.bSplineKnotMultiplicityVisible = hGrpsk->GetBool(parametername.c_str(), true);
else if constexpr (visibilityparameter == OverlayVisibilityParameter::BSplinePoleWeightVisible)
Client.overlayParameters.bSplinePoleWeightVisible = hGrpsk->GetBool(parametername.c_str(), true);
Client.overlayParameters.visibleInformationChanged = true;
}
void EditModeCoinManager::ParameterObserver::updateElementSizeParameters(const std::string & parametername)
{
(void) parametername;
//Add scaling to Constraint icons
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
double viewScalingFactor = hGrp->GetFloat("ViewScalingFactor", 1.0);
viewScalingFactor = Base::clamp<double>(viewScalingFactor, 0.5, 5.0);
int markersize = hGrp->GetInt("MarkerSize", 7);
int defaultFontSizePixels = Client.defaultApplicationFontSizePixels(); // returns height in pixels, not points
int sketcherfontSize = hGrp->GetInt("EditSketcherFontSize", defaultFontSizePixels);
int dpi = Client.getApplicationLogicalDPIX();
// simple scaling factor for hardcoded pixel values in the Sketcher
Client.drawingParameters.pixelScalingFactor = viewScalingFactor * dpi / 96; // 96 ppi is the standard pixel density for which pixel quantities were calculated
// Coin documentation indicates the size of a font is:
// SoSFFloat SoFont::size Size of font. Defaults to 10.0.
//
// For 2D rendered bitmap fonts (like for SoText2), this value is the height of a character in screen pixels. For 3D text, this value is the world-space coordinates height of a character in the current units setting (see documentation for SoUnits node).
//
// However, with hdpi monitors, the coin font labels do not respect the size passed in pixels:
// https://forum.freecadweb.org/viewtopic.php?f=3&t=54347&p=467610#p467610
// https://forum.freecadweb.org/viewtopic.php?f=10&t=49972&start=40#p467471
//
// Because I (abdullah) have 96 dpi logical, 82 dpi physical, and I see a 35px font setting for a "1" in a datum label as 34px,
// and I see kilsore and Elyas screenshots showing 41px and 61px in higher resolution monitors for the same configuration, I think
// that coin pixel size has to be corrected by the logical dpi of the monitor. The rationale is that: a) it obviously needs dpi
// correction, b) with physical dpi, the ratio of representation between kilsore and me is too far away.
//
// This means that the following correction does not have a documented basis, but appears necessary so that the Sketcher is usable in
// HDPI monitors.
Client.drawingParameters.coinFontSize = std::lround(sketcherfontSize * 96.0f / dpi);
Client.drawingParameters.constraintIconSize = std::lround(0.8 * sketcherfontSize);
// For marker size the global default is used.
//
// Rationale:
// -> Other WBs use the default value as is
// -> If a user has a HDPI, he will eventually change the value for the other WBs
// -> If we correct the value here in addition, we would get two times a resize
Client.drawingParameters.markerSize = markersize;
Client.updateInventorNodeSizes();
}
void EditModeCoinManager::ParameterObserver::updateColor(SbColor &sbcolor, const std::string &parametername)
{
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
float transparency = 0.f;
unsigned long color = (unsigned long)(sbcolor.getPackedValue());
color = hGrp->GetUnsigned(parametername.c_str(), color);
sbcolor.setPackedValue((uint32_t)color, transparency);
}
void EditModeCoinManager::ParameterObserver::subscribeToParameters()
{
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
hGrp->Attach(this);
ParameterGrp::handle hGrpsk = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
hGrpsk->Attach(this);
ParameterGrp::handle hGrpp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
hGrpp->Attach(this);
ParameterGrp::handle hGrpskg = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
hGrpskg->Attach(this);
}
void EditModeCoinManager::ParameterObserver::unsubscribeToParameters()
{
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
hGrp->Detach(this);
ParameterGrp::handle hGrpsk = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
hGrpsk->Detach(this);
ParameterGrp::handle hGrpp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
hGrpp->Detach(this);
ParameterGrp::handle hGrpskg = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
hGrpskg->Detach(this);
}
void EditModeCoinManager::ParameterObserver::OnChange(Base::Subject<const char*> &rCaller, const char * sReason)
{
(void) rCaller;
auto key = str2updatefunction.find(sReason);
if( key != str2updatefunction.end() ) {
auto string = key->first;
auto function = key->second;
function(string);
Client.redrawViewProvider(); // redraw with non-temporal geometry
}
}
//**************************** EditModeCoinManager class ******************************
EditModeCoinManager::EditModeCoinManager(ViewProviderSketch &vp):viewProvider(vp) {
pEditModeConstraintCoinManager = std::make_unique<EditModeConstraintCoinManager>(viewProvider,
drawingParameters,
geometryLayerParameters,
constraintParameters,
editModeScenegraphNodes,
coinMapping);
pEditModeGeometryCoinManager = std::make_unique<EditModeGeometryCoinManager>( viewProvider,
drawingParameters,
geometryLayerParameters,
analysisResults,
editModeScenegraphNodes,
coinMapping);
// Create Edit Mode Scenograph
createEditModeInventorNodes();
// Create parameter observer and initialise watched parameters
pObserver = std::make_unique<EditModeCoinManager::ParameterObserver>(*this);
}
EditModeCoinManager::~EditModeCoinManager()
{
Gui::coinRemoveAllChildren(editModeScenegraphNodes.EditRoot);
ViewProviderSketchCoinAttorney::removeNodeFromRoot(viewProvider, editModeScenegraphNodes.EditRoot);
editModeScenegraphNodes.EditRoot->unref();
}
/***** Temporary edit curves and markers *****/
void EditModeCoinManager::drawEditMarkers(const std::vector<Base::Vector2d> &EditMarkers, unsigned int augmentationlevel)
{
// determine marker size
int augmentedmarkersize = drawingParameters.markerSize;
auto supportedsizes = Gui::Inventor::MarkerBitmaps::getSupportedSizes("CIRCLE_LINE");
auto defaultmarker = std::find(supportedsizes.begin(), supportedsizes.end(), drawingParameters.markerSize);
if(defaultmarker != supportedsizes.end()) {
auto validAugmentationLevels = std::distance(defaultmarker,supportedsizes.end());
if(augmentationlevel >= validAugmentationLevels)
augmentationlevel = validAugmentationLevels - 1;
augmentedmarkersize = *std::next(defaultmarker, augmentationlevel);
}
editModeScenegraphNodes.EditMarkerSet->markerIndex.startEditing();
editModeScenegraphNodes.EditMarkerSet->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_LINE", augmentedmarkersize);
// add the points to set
editModeScenegraphNodes.EditMarkersCoordinate->point.setNum(EditMarkers.size());
editModeScenegraphNodes.EditMarkersMaterials->diffuseColor.setNum(EditMarkers.size());
SbVec3f *verts = editModeScenegraphNodes.EditMarkersCoordinate->point.startEditing();
SbColor *color = editModeScenegraphNodes.EditMarkersMaterials->diffuseColor.startEditing();
int i=0; // setting up the line set
for (std::vector<Base::Vector2d>::const_iterator it = EditMarkers.begin(); it != EditMarkers.end(); ++it,i++) {
verts[i].setValue(it->x, it->y, drawingParameters.zEdit);
color[i] = drawingParameters.InformationColor;
}
editModeScenegraphNodes.EditMarkersCoordinate->point.finishEditing();
editModeScenegraphNodes.EditMarkersMaterials->diffuseColor.finishEditing();
editModeScenegraphNodes.EditMarkerSet->markerIndex.finishEditing();
}
void EditModeCoinManager::drawEdit(const std::vector<Base::Vector2d> &EditCurve)
{
editModeScenegraphNodes.EditCurveSet->numVertices.setNum(1);
editModeScenegraphNodes.EditCurvesCoordinate->point.setNum(EditCurve.size());
editModeScenegraphNodes.EditCurvesMaterials->diffuseColor.setNum(EditCurve.size());
SbVec3f *verts = editModeScenegraphNodes.EditCurvesCoordinate->point.startEditing();
int32_t *index = editModeScenegraphNodes.EditCurveSet->numVertices.startEditing();
SbColor *color = editModeScenegraphNodes.EditCurvesMaterials->diffuseColor.startEditing();
int i=0; // setting up the line set
for (std::vector<Base::Vector2d>::const_iterator it = EditCurve.begin(); it != EditCurve.end(); ++it,i++) {
verts[i].setValue(it->x,it->y, drawingParameters.zEdit);
color[i] = drawingParameters.CreateCurveColor;
}
index[0] = EditCurve.size();
editModeScenegraphNodes.EditCurvesCoordinate->point.finishEditing();
editModeScenegraphNodes.EditCurveSet->numVertices.finishEditing();
editModeScenegraphNodes.EditCurvesMaterials->diffuseColor.finishEditing();
}
void EditModeCoinManager::setPositionText(const Base::Vector2d &Pos, const SbString &text)
{
editModeScenegraphNodes.textX->string = text;
editModeScenegraphNodes.textPos->translation = SbVec3f(Pos.x, Pos.y, drawingParameters.zText);
}
void EditModeCoinManager::setPositionText(const Base::Vector2d &Pos)
{
SbString text;
text.sprintf(" (%.1f,%.1f)", Pos.x, Pos.y);
setPositionText(Pos,text);
}
void EditModeCoinManager::resetPositionText(void)
{
editModeScenegraphNodes.textX->string = "";
}
void EditModeCoinManager::setAxisPickStyle(bool on)
{
if (on)
editModeScenegraphNodes.pickStyleAxes->style = SoPickStyle::SHAPE;
else
editModeScenegraphNodes.pickStyleAxes->style = SoPickStyle::UNPICKABLE;
}
EditModeCoinManager::PreselectionResult EditModeCoinManager::detectPreselection(SoPickedPoint * Point, const SbVec2s &cursorPos)
{
EditModeCoinManager::PreselectionResult result;
if(!Point)
return result;
//Base::Console().Log("Point pick\n");
SoPath *path = Point->getPath();
SoNode *tail = path->getTail(); // Tail is directly the node containing points and curves
for(int l = 0; l < geometryLayerParameters.CoinLayers; l++) {
// checking for a hit in the points
if (tail == editModeScenegraphNodes.PointSet[l]) {
const SoDetail *point_detail = Point->getDetail(editModeScenegraphNodes.PointSet[l]);
if (point_detail && point_detail->getTypeId() == SoPointDetail::getClassTypeId()) {
// get the index
int pindex = static_cast<const SoPointDetail *>(point_detail)->getCoordinateIndex();
result.PointIndex = coinMapping.getPointVertexId(pindex, l); // returns -1 for root, global VertexId for the rest of vertices.
if (result.PointIndex == -1)
result.Cross = PreselectionResult::Axes::RootPoint;
return result;
}
}
// checking for a hit in the curves
if (tail == editModeScenegraphNodes.CurveSet[l]) {
const SoDetail *curve_detail = Point->getDetail(editModeScenegraphNodes.CurveSet[l]);
if (curve_detail && curve_detail->getTypeId() == SoLineDetail::getClassTypeId()) {
// get the index
int curveIndex = static_cast<const SoLineDetail *>(curve_detail)->getLineIndex();
result.GeoIndex = coinMapping.getCurveGeoId(curveIndex, l);
return result;
}
}
}
// checking for a hit in the axes
if (tail == editModeScenegraphNodes.RootCrossSet) {
const SoDetail *cross_detail = Point->getDetail(editModeScenegraphNodes.RootCrossSet);
if (cross_detail && cross_detail->getTypeId() == SoLineDetail::getClassTypeId()) {
// get the index (reserve index 0 for root point)
int CrossIndex = static_cast<const SoLineDetail *>(cross_detail)->getLineIndex();
if(CrossIndex == 0)
result.Cross = PreselectionResult::Axes::HorizontalAxis;
else if(CrossIndex == 1)
result.Cross = PreselectionResult::Axes::VerticalAxis;
return result;
}
}
// checking if a constraint is hit
result.ConstrIndices = pEditModeConstraintCoinManager->detectPreselectionConstr(Point, cursorPos);
return result;
}
SoGroup* EditModeCoinManager::getSelectedConstraints()
{
SoGroup* group = new SoGroup();
group->ref();
for (int i=0; i < editModeScenegraphNodes.constrGroup->getNumChildren(); i++) {
if (ViewProviderSketchCoinAttorney::isConstraintSelected(viewProvider, i)) {
SoSeparator *sep = pEditModeConstraintCoinManager->getConstraintIdSeparator(i);
if (sep)
group->addChild(sep);
}
}
return group;
}
/***** update coin nodes *****/
void EditModeCoinManager::processGeometryConstraintsInformationOverlay(const GeoListFacade & geolistfacade, bool rebuildinformationlayer)
{
overlayParameters.rebuildInformationLayer = rebuildinformationlayer;
pEditModeGeometryCoinManager->processGeometry(geolistfacade);
updateOverlayParameters();
processGeometryInformationOverlay(geolistfacade);
updateAxesLength();
updateGridExtent();
pEditModeConstraintCoinManager->processConstraints(geolistfacade);
}
void EditModeCoinManager::updateOverlayParameters()
{
if ( (analysisResults.combRepresentationScale > (2 * overlayParameters.currentBSplineCombRepresentationScale)) ||
(analysisResults.combRepresentationScale < (overlayParameters.currentBSplineCombRepresentationScale / 2)))
overlayParameters.currentBSplineCombRepresentationScale = analysisResults.combRepresentationScale ;
}
void EditModeCoinManager::processGeometryInformationOverlay(const GeoListFacade & geolistfacade)
{
if(overlayParameters.rebuildInformationLayer) {
// every time we start with empty information overlay
Gui::coinRemoveAllChildren(editModeScenegraphNodes.infoGroup);
}
auto ioconv = EditModeInformationOverlayCoinConverter(editModeScenegraphNodes.infoGroup, overlayParameters, drawingParameters);
// geometry information layer for bsplines, as they need a second round now that max curvature is known
for (auto geoid : analysisResults.bsplineGeoIds) {
const Part::Geometry *geo = geolistfacade.getGeometryFromGeoId(geoid);
ioconv.convert(geo, geoid);
}
overlayParameters.visibleInformationChanged = false; // just updated
}
void EditModeCoinManager::updateAxesLength()
{
editModeScenegraphNodes.RootCrossCoordinate->point.set1Value(0,SbVec3f(-analysisResults.boundingBoxMagnitudeOrder, 0.0f, drawingParameters.zCross));
editModeScenegraphNodes.RootCrossCoordinate->point.set1Value(1,SbVec3f(analysisResults.boundingBoxMagnitudeOrder, 0.0f, drawingParameters.zCross));
editModeScenegraphNodes.RootCrossCoordinate->point.set1Value(2,SbVec3f(0.0f, -analysisResults.boundingBoxMagnitudeOrder, drawingParameters.zCross));
editModeScenegraphNodes.RootCrossCoordinate->point.set1Value(3,SbVec3f(0.0f, analysisResults.boundingBoxMagnitudeOrder, drawingParameters.zCross));
}
void EditModeCoinManager::updateGridExtent()
{
float dMagF = analysisResults.boundingBoxMagnitudeOrder;
ViewProviderSketchCoinAttorney::updateGridExtent(viewProvider,-dMagF, dMagF, -dMagF, dMagF);
}
void EditModeCoinManager::updateColor()
{
auto geolistfacade = ViewProviderSketchCoinAttorney::getGeoListFacade(viewProvider);
updateColor(geolistfacade);
}
void EditModeCoinManager::updateColor(const GeoListFacade & geolistfacade)
{
bool sketchinvalid = ViewProviderSketchCoinAttorney::isSketchInvalid(viewProvider);
pEditModeGeometryCoinManager->updateGeometryColor(geolistfacade, sketchinvalid);
// update constraint color
auto constraints = ViewProviderSketchCoinAttorney::getConstraints(viewProvider);
if(ViewProviderSketchCoinAttorney::haveConstraintsInvalidGeometry(viewProvider))
return;
pEditModeConstraintCoinManager->updateConstraintColor(constraints);
}
void EditModeCoinManager::createEditModeInventorNodes()
{
// 1 - Create the edit root node
editModeScenegraphNodes.EditRoot = new SoSeparator;
editModeScenegraphNodes.EditRoot->ref(); // Node is unref in the destructor of EditModeCoinManager
editModeScenegraphNodes.EditRoot->setName("Sketch_EditRoot");
ViewProviderSketchCoinAttorney::addNodeToRoot(viewProvider, editModeScenegraphNodes.EditRoot);
editModeScenegraphNodes.EditRoot->renderCaching = SoSeparator::OFF ;
// Create Geometry Coin nodes ++++++++++++++++++++++++++++++++++++++
pEditModeGeometryCoinManager->createEditModeInventorNodes();
// stuff for the RootCross lines +++++++++++++++++++++++++++++++++++++++
SoGroup* crossRoot = new Gui::SoSkipBoundingGroup;
editModeScenegraphNodes.pickStyleAxes = new SoPickStyle();
editModeScenegraphNodes.pickStyleAxes->style = SoPickStyle::SHAPE;
crossRoot->addChild(editModeScenegraphNodes.pickStyleAxes);
editModeScenegraphNodes.EditRoot->addChild(crossRoot);
auto MtlBind = new SoMaterialBinding;
MtlBind->setName("RootCrossMaterialBinding");
MtlBind->value = SoMaterialBinding::PER_FACE;
crossRoot->addChild(MtlBind);
editModeScenegraphNodes.RootCrossDrawStyle = new SoDrawStyle;
editModeScenegraphNodes.RootCrossDrawStyle->setName("RootCrossDrawStyle");
editModeScenegraphNodes.RootCrossDrawStyle->lineWidth = 2 * drawingParameters.pixelScalingFactor;
crossRoot->addChild(editModeScenegraphNodes.RootCrossDrawStyle);
editModeScenegraphNodes.RootCrossMaterials = new SoMaterial;
editModeScenegraphNodes.RootCrossMaterials->setName("RootCrossMaterials");
editModeScenegraphNodes.RootCrossMaterials->diffuseColor.set1Value(0, drawingParameters.CrossColorH);
editModeScenegraphNodes.RootCrossMaterials->diffuseColor.set1Value(1, drawingParameters.CrossColorV);
crossRoot->addChild(editModeScenegraphNodes.RootCrossMaterials);
editModeScenegraphNodes.RootCrossCoordinate = new SoCoordinate3;
editModeScenegraphNodes.RootCrossCoordinate->setName("RootCrossCoordinate");
crossRoot->addChild(editModeScenegraphNodes.RootCrossCoordinate);
editModeScenegraphNodes.RootCrossSet = new SoLineSet;
editModeScenegraphNodes.RootCrossSet->setName("RootCrossLineSet");
crossRoot->addChild(editModeScenegraphNodes.RootCrossSet);
// stuff for the EditCurves +++++++++++++++++++++++++++++++++++++++
SoSeparator* editCurvesRoot = new SoSeparator;
editModeScenegraphNodes.EditRoot->addChild(editCurvesRoot);
editModeScenegraphNodes.EditCurvesMaterials = new SoMaterial;
editModeScenegraphNodes.EditCurvesMaterials->setName("EditCurvesMaterials");
editCurvesRoot->addChild(editModeScenegraphNodes.EditCurvesMaterials);
editModeScenegraphNodes.EditCurvesCoordinate = new SoCoordinate3;
editModeScenegraphNodes.EditCurvesCoordinate->setName("EditCurvesCoordinate");
editCurvesRoot->addChild(editModeScenegraphNodes.EditCurvesCoordinate);
editModeScenegraphNodes.EditCurvesDrawStyle = new SoDrawStyle;
editModeScenegraphNodes.EditCurvesDrawStyle->setName("EditCurvesDrawStyle");
editModeScenegraphNodes.EditCurvesDrawStyle->lineWidth = 3 * drawingParameters.pixelScalingFactor;
editCurvesRoot->addChild(editModeScenegraphNodes.EditCurvesDrawStyle);
editModeScenegraphNodes.EditCurveSet = new SoLineSet;
editModeScenegraphNodes.EditCurveSet->setName("EditCurveLineSet");
editCurvesRoot->addChild(editModeScenegraphNodes.EditCurveSet);
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
float transparency;
SbColor cursorTextColor(0,0,1);
cursorTextColor.setPackedValue((uint32_t)hGrp->GetUnsigned("CursorTextColor", cursorTextColor.getPackedValue()), transparency);
// stuff for the EditMarkers +++++++++++++++++++++++++++++++++++++++
SoSeparator* editMarkersRoot = new SoSeparator;
editModeScenegraphNodes.EditRoot->addChild(editMarkersRoot);
editModeScenegraphNodes.EditMarkersMaterials = new SoMaterial;
editModeScenegraphNodes.EditMarkersMaterials->setName("EditMarkersMaterials");
editMarkersRoot->addChild(editModeScenegraphNodes.EditMarkersMaterials);
editModeScenegraphNodes.EditMarkersCoordinate = new SoCoordinate3;
editModeScenegraphNodes.EditMarkersCoordinate->setName("EditMarkersCoordinate");
editMarkersRoot->addChild(editModeScenegraphNodes.EditMarkersCoordinate);
editModeScenegraphNodes.EditMarkersDrawStyle = new SoDrawStyle;
editModeScenegraphNodes.EditMarkersDrawStyle->setName("EditMarkersDrawStyle");
editModeScenegraphNodes.EditMarkersDrawStyle->pointSize = 8 * drawingParameters.pixelScalingFactor;
editMarkersRoot->addChild(editModeScenegraphNodes.EditMarkersDrawStyle);
editModeScenegraphNodes.EditMarkerSet = new SoMarkerSet;
editModeScenegraphNodes.EditMarkerSet->setName("EditMarkerSet");
editModeScenegraphNodes.EditMarkerSet->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_LINE", drawingParameters.markerSize);
editMarkersRoot->addChild(editModeScenegraphNodes.EditMarkerSet);
// stuff for the edit coordinates ++++++++++++++++++++++++++++++++++++++
SoSeparator *Coordsep = new SoSeparator();
SoPickStyle* ps = new SoPickStyle();
ps->style.setValue(SoPickStyle::UNPICKABLE);
Coordsep->addChild(ps);
Coordsep->setName("CoordSeparator");
// no caching for frequently-changing data structures
Coordsep->renderCaching = SoSeparator::OFF;
SoMaterial *CoordTextMaterials = new SoMaterial;
CoordTextMaterials->setName("CoordTextMaterials");
CoordTextMaterials->diffuseColor = cursorTextColor;
Coordsep->addChild(CoordTextMaterials);
SoFont *font = new SoFont();
font->size.setValue(drawingParameters.coinFontSize);
Coordsep->addChild(font);
editModeScenegraphNodes.textPos = new SoTranslation();
Coordsep->addChild(editModeScenegraphNodes.textPos);
editModeScenegraphNodes.textX = new SoText2();
editModeScenegraphNodes.textX->justification = SoText2::LEFT;
editModeScenegraphNodes.textX->string = "";
Coordsep->addChild(editModeScenegraphNodes.textX);
editModeScenegraphNodes.EditRoot->addChild(Coordsep);
// coin nodes for the constraints +++++++++++++++++++++++++++++++++++++++++++++++++++
pEditModeConstraintCoinManager->createEditModeInventorNodes();
// group node for the Geometry information visual +++++++++++++++++++++++++++++++++++
MtlBind = new SoMaterialBinding;
MtlBind->setName("InformationMaterialBinding");
MtlBind->value = SoMaterialBinding::OVERALL ;
editModeScenegraphNodes.EditRoot->addChild(MtlBind);
// use small line width for the information visual
editModeScenegraphNodes.InformationDrawStyle = new SoDrawStyle;
editModeScenegraphNodes.InformationDrawStyle->setName("InformationDrawStyle");
editModeScenegraphNodes.InformationDrawStyle->lineWidth = 1 * drawingParameters.pixelScalingFactor;
editModeScenegraphNodes.EditRoot->addChild(editModeScenegraphNodes.InformationDrawStyle);
// add the group where all the information entity has its SoSeparator
editModeScenegraphNodes.infoGroup = new SoGroup();
editModeScenegraphNodes.infoGroup->setName("InformationGroup");
editModeScenegraphNodes.EditRoot->addChild(editModeScenegraphNodes.infoGroup);
}
void EditModeCoinManager::redrawViewProvider()
{
viewProvider.draw(false,false);
}
/************************ Delegated constraint public interface **********/
// public function that triggers drawing of most constraint icons
void EditModeCoinManager::drawConstraintIcons()
{
pEditModeConstraintCoinManager->drawConstraintIcons();
}
void EditModeCoinManager::drawConstraintIcons(const GeoList & geolist)
{
pEditModeConstraintCoinManager->drawConstraintIcons(geolist);
}
void EditModeCoinManager::updateVirtualSpace()
{
pEditModeConstraintCoinManager->updateVirtualSpace();
}
/************************ Resizing of coin nodes ************************/
int EditModeCoinManager::defaultApplicationFontSizePixels() const {
return ViewProviderSketchCoinAttorney::defaultApplicationFontSizePixels(viewProvider);
}
int EditModeCoinManager::getApplicationLogicalDPIX() const {
return ViewProviderSketchCoinAttorney::getApplicationLogicalDPIX(viewProvider);
}
void EditModeCoinManager::updateInventorNodeSizes()
{
for(int l = 0; l < geometryLayerParameters.CoinLayers; l++) {
editModeScenegraphNodes.PointsDrawStyle[l]->pointSize = 8 * drawingParameters.pixelScalingFactor;
editModeScenegraphNodes.PointSet[l]->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_FILLED", drawingParameters.markerSize);
editModeScenegraphNodes.CurvesDrawStyle[l]->lineWidth = 3 * drawingParameters.pixelScalingFactor;
}
editModeScenegraphNodes.RootCrossDrawStyle->lineWidth = 2 * drawingParameters.pixelScalingFactor;
editModeScenegraphNodes.EditCurvesDrawStyle->lineWidth = 3 * drawingParameters.pixelScalingFactor;
editModeScenegraphNodes.EditMarkersDrawStyle->pointSize = 8 * drawingParameters.pixelScalingFactor;
editModeScenegraphNodes.EditMarkerSet->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_LINE", drawingParameters.markerSize);
editModeScenegraphNodes.ConstraintDrawStyle->lineWidth = 1 * drawingParameters.pixelScalingFactor;
editModeScenegraphNodes.InformationDrawStyle->lineWidth = 1 * drawingParameters.pixelScalingFactor;
pEditModeConstraintCoinManager->rebuildConstraintNodes();
}
/************************ Edit node access ************************/
SoSeparator* EditModeCoinManager::getRootEditNode()
{
return editModeScenegraphNodes.EditRoot;
}