Files
create/src/Mod/Sketcher/Gui/EditModeGeometryCoinManager.cpp
Abdullah Tahiri 91070330d8 Sketcher: Fix overlapped points not selecting/preselecting
=========================================================

Fixes an issue reported directly by Chrisb.

On overlapping points, such as due to coincidence, selection and
preselection (e.g. from the ElementsWidget) is not shown for those
points which are rendered first.

Solution: To raise the points to the highlight height.
2023-04-22 15:07:34 +02:00

559 lines
25 KiB
C++

/***************************************************************************
* 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 <memory>
# include <Inventor/SbVec3f.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoLineSet.h>
# include <Inventor/nodes/SoMarkerSet.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoSeparator.h>
#endif // #ifndef _PreComp_
#include <Gui/Inventor/MarkerBitmaps.h>
#include <Gui/Inventor/SmSwitchboard.h>
#include <Mod/Sketcher/App/Constraint.h>
#include <Mod/Sketcher/App/GeoEnum.h>
#include <Mod/Sketcher/App/GeoList.h>
#include <Mod/Sketcher/App/GeometryFacade.h>
#include <Mod/Sketcher/App/SolverGeometryExtension.h>
#include "EditModeGeometryCoinManager.h"
#include "EditModeGeometryCoinConverter.h"
#include "ViewProviderSketchCoinAttorney.h"
using namespace SketcherGui;
using namespace Sketcher;
//**************************** EditModeGeometryCoinManager class ******************************
EditModeGeometryCoinManager::EditModeGeometryCoinManager( ViewProviderSketch &vp,
DrawingParameters & drawingParams,
GeometryLayerParameters & geometryLayerParams,
AnalysisResults & analysisResultStruct,
EditModeScenegraphNodes & editModeScenegraph,
CoinMapping & coinMap):
viewProvider(vp),
drawingParameters(drawingParams),
geometryLayerParameters(geometryLayerParams),
analysisResults(analysisResultStruct),
editModeScenegraphNodes(editModeScenegraph),
coinMapping(coinMap)
{}
EditModeGeometryCoinManager::~EditModeGeometryCoinManager()
{}
void EditModeGeometryCoinManager::processGeometry(const GeoListFacade & geolistfacade)
{
// enable all layers
editModeScenegraphNodes.PointsGroup->enable.setNum(geometryLayerParameters.getCoinLayerCount());
editModeScenegraphNodes.CurvesGroup->enable.setNum(geometryLayerParameters.getCoinLayerCount());
SbBool *swsp = editModeScenegraphNodes.PointsGroup->enable.startEditing();
SbBool *swsc = editModeScenegraphNodes.CurvesGroup->enable.startEditing();
auto setEnableLayer = [swsp, swsc](int l, bool enabled) {
swsp[l] = enabled; // layer defaults to enabled
swsc[l] = enabled; // layer defaults to enabled
};
auto layersconfigurations = viewProvider.VisualLayerList.getValues();
for(auto l=0; l<geometryLayerParameters.getCoinLayerCount(); l++){
setEnableLayer(l,layersconfigurations[l].isVisible());
}
editModeScenegraphNodes.PointsGroup->enable.finishEditing();
editModeScenegraphNodes.CurvesGroup->enable.finishEditing();
// Define the coin nodes that will be filled in with the geometry layers
GeometryLayerNodes geometrylayernodes {
editModeScenegraphNodes.PointsMaterials,
editModeScenegraphNodes.PointsCoordinate,
editModeScenegraphNodes.CurvesMaterials,
editModeScenegraphNodes.CurvesCoordinate,
editModeScenegraphNodes.CurveSet
};
// process geometry layers
EditModeGeometryCoinConverter gcconv(viewProvider, geometrylayernodes, drawingParameters, geometryLayerParameters, coinMapping);
gcconv.convert(geolistfacade);
// set cross coordinates
editModeScenegraphNodes.RootCrossSet->numVertices.set1Value(0,2);
editModeScenegraphNodes.RootCrossSet->numVertices.set1Value(1,2);
analysisResults.combRepresentationScale = gcconv.getCombRepresentationScale();
analysisResults.boundingBoxMagnitudeOrder = exp(ceil(log(std::abs(gcconv.getBoundingBoxMaxMagnitude()))));
analysisResults.bsplineGeoIds = gcconv.getBSplineGeoIds();
}
void EditModeGeometryCoinManager::updateGeometryColor(const GeoListFacade & geolistfacade, bool issketchinvalid)
{
// Lambdas for convenience retrieval of geometry information
auto isConstructionGeom = [&geolistfacade](int GeoId) {
auto geom = geolistfacade.getGeometryFacadeFromGeoId(GeoId);
if (geom)
return geom->getConstruction();
return false;
};
auto isDefinedGeomPoint = [&geolistfacade](int GeoId) {
auto geom = geolistfacade.getGeometryFacadeFromGeoId(GeoId);
if (geom)
return geom->isGeoType(Part::GeomPoint::getClassTypeId()) && !geom->getConstruction();
return false;
};
auto isInternalAlignedGeom = [&geolistfacade](int GeoId) {
auto geom = geolistfacade.getGeometryFacadeFromGeoId(GeoId);
if (geom) {
return geom->isInternalAligned();
}
return false;
};
auto isFullyConstraintElement = [&geolistfacade](int GeoId) {
auto geom = geolistfacade.getGeometryFacadeFromGeoId(GeoId);
if(geom) {
if(geom->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) {
auto solvext = std::static_pointer_cast<const Sketcher::SolverGeometryExtension>(
geom->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock());
return (solvext->getGeometry() == Sketcher::SolverGeometryExtension::FullyConstraint);
}
}
return false;
};
// Update Colors
SbColor *crosscolor = editModeScenegraphNodes.RootCrossMaterials->diffuseColor.startEditing();
auto viewOrientationFactor = ViewProviderSketchCoinAttorney::getViewOrientationFactor(viewProvider);
for(auto l=0; l<geometryLayerParameters.getCoinLayerCount(); l++) {
int PtNum = editModeScenegraphNodes.PointsMaterials[l]->diffuseColor.getNum();
SbColor *pcolor = editModeScenegraphNodes.PointsMaterials[l]->diffuseColor.startEditing();
int CurvNum = editModeScenegraphNodes.CurvesMaterials[l]->diffuseColor.getNum();
SbColor *color = editModeScenegraphNodes.CurvesMaterials[l]->diffuseColor.startEditing();
SbVec3f *verts = editModeScenegraphNodes.CurvesCoordinate[l]->point.startEditing();
SbVec3f *pverts = editModeScenegraphNodes.PointsCoordinate[l]->point.startEditing();
float x,y,z;
// colors of the point set
if( issketchinvalid ) {
for (int i=0; i < PtNum; i++)
pcolor[i] = drawingParameters.InvalidSketchColor;
}
else {
for (int i=0; i < PtNum; i++) {
if ( !(i == 0 && l == 0) && ViewProviderSketchCoinAttorney::isSketchFullyConstrained(viewProvider)) {// root point is not coloured
pcolor[i] = drawingParameters.FullyConstrainedColor;
}
else {
int GeoId = coinMapping.getPointGeoId(i, l);
bool constrainedElement = isFullyConstraintElement(GeoId);
if(isInternalAlignedGeom(GeoId)) {
if(constrainedElement)
pcolor[i] = drawingParameters.FullyConstraintInternalAlignmentColor;
else
pcolor[i] = drawingParameters.InternalAlignedGeoColor;
}
else {
if(!isDefinedGeomPoint(GeoId)) {
if(constrainedElement)
pcolor[i] = drawingParameters.FullyConstraintConstructionPointColor;
else
pcolor[i] = drawingParameters.VertexColor;
}
else { // this is a defined GeomPoint
if(constrainedElement)
pcolor[i] = drawingParameters.FullyConstraintElementColor;
else
pcolor[i] = drawingParameters.CurveColor;
}
}
}
}
}
// update rendering height of points
auto getRenderHeight = [this](DrawingParameters::GeometryRendering renderingtype, float toprendering, float midrendering, float lowrendering) {
if(drawingParameters.topRenderingGeometry == renderingtype)
return toprendering;
else if(drawingParameters.midRenderingGeometry == renderingtype)
return midrendering;
else
return lowrendering;
};
float zNormPoint = getRenderHeight(DrawingParameters::GeometryRendering::NormalGeometry,
drawingParameters.zHighPoints,
drawingParameters.zLowPoints,
drawingParameters.zLowPoints);
float zConstrPoint = getRenderHeight(DrawingParameters::GeometryRendering::Construction,
drawingParameters.zHighPoints,
drawingParameters.zLowPoints,
drawingParameters.zLowPoints);
for (int i=0; i < PtNum; i++) { // 0 is the origin
if( i == 0 && l == 0 ) { // reset root point to lowest
pverts[i].setValue(0, 0, viewOrientationFactor * drawingParameters.zRootPoint);
}
else {
pverts[i].getValue(x,y,z);
auto geom = geolistfacade.getGeometryFacadeFromGeoId(coinMapping.getPointGeoId(i, l));
if(geom) {
if(geom->getConstruction())
pverts[i].setValue(x,y,viewOrientationFactor * zConstrPoint);
else
pverts[i].setValue(x,y,viewOrientationFactor * zNormPoint);
}
}
}
auto preselectpoint = ViewProviderSketchCoinAttorney::getPreselectPoint(viewProvider);
auto preselectcross = ViewProviderSketchCoinAttorney::getPreselectCross(viewProvider);
auto preselectcurve = ViewProviderSketchCoinAttorney::getPreselectCurve(viewProvider);
auto raisePoint = [](SbVec3f & point, float height) {
float x, y, z;
point.getValue(x, y, z);
point.setValue(x, y, height);
};
MultiFieldId preselectpointmfid;
if ( preselectcross == 0) {
if(l == 0) // cross only in layer 0
pcolor[0] = drawingParameters.PreselectColor;
}
else if (preselectpoint != -1) {
preselectpointmfid = coinMapping.getIndexLayer(preselectpoint);
if (MultiFieldId::Invalid != preselectpointmfid &&
preselectpointmfid.layerId == l &&
preselectpointmfid.fieldIndex < PtNum) {
pcolor[preselectpointmfid.fieldIndex] = drawingParameters.PreselectColor;
raisePoint(pverts[preselectpointmfid.fieldIndex], drawingParameters.zHighlight);
}
}
ViewProviderSketchCoinAttorney::executeOnSelectionPointSet(viewProvider,
[pcolor, pverts, PtNum, preselectpointmfid, layerId = l, &coinMapping = coinMapping, drawingParameters = this->drawingParameters, raisePoint](const int i) {
auto pointindex = coinMapping.getIndexLayer(i);
if (layerId == pointindex.layerId && pointindex.fieldIndex >= 0 && pointindex.fieldIndex < PtNum) {
pcolor[pointindex.fieldIndex] = (preselectpointmfid == pointindex)
? drawingParameters.PreselectSelectedColor : drawingParameters.SelectColor;
raisePoint(pverts[pointindex.fieldIndex], drawingParameters.zHighlight);
}
});
// update colors and rendering height of the curves
float zNormLine = getRenderHeight(DrawingParameters::GeometryRendering::NormalGeometry,
drawingParameters.zHighLines,
drawingParameters.zMidLines,
drawingParameters.zLowLines);
float zConstrLine = getRenderHeight(DrawingParameters::GeometryRendering::Construction,
drawingParameters.zHighLines,
drawingParameters.zMidLines,
drawingParameters.zLowLines);
float zExtLine = getRenderHeight(DrawingParameters::GeometryRendering::ExternalGeometry,
drawingParameters.zHighLines,
drawingParameters.zMidLines,
drawingParameters.zLowLines);
int j=0; // vertexindex
for (int i=0; i < CurvNum; i++) {
int GeoId = coinMapping.getCurveGeoId(i, l);
// CurvId has several vertices associated to 1 material
//edit->CurveSet->numVertices => [i] indicates number of vertex for line i.
int indexes = (editModeScenegraphNodes.CurveSet[l]->numVertices[i]);
bool selected = ViewProviderSketchCoinAttorney::isCurveSelected(viewProvider, GeoId);
bool preselected = (preselectcurve == GeoId);
bool constrainedElement = isFullyConstraintElement(GeoId);
if (selected && preselected) {
color[i] = drawingParameters.PreselectSelectedColor;
for (int k=j; j<k+indexes; j++) {
verts[j].getValue(x,y,z);
verts[j] = SbVec3f(x,y,viewOrientationFactor * drawingParameters.zHighLine);
}
}
else if (selected){
color[i] = drawingParameters.SelectColor;
for (int k=j; j<k+indexes; j++) {
verts[j].getValue(x,y,z);
verts[j] = SbVec3f(x,y,viewOrientationFactor * drawingParameters.zHighLine);
}
}
else if (preselected){
color[i] = drawingParameters.PreselectColor;
for (int k=j; j<k+indexes; j++) {
verts[j].getValue(x,y,z);
verts[j] = SbVec3f(x,y,viewOrientationFactor * drawingParameters.zHighLine);
}
}
else if (GeoId <= Sketcher::GeoEnum::RefExt) { // external Geometry
color[i] = drawingParameters.CurveExternalColor;
for (int k=j; j<k+indexes; j++) {
verts[j].getValue(x,y,z);
verts[j] = SbVec3f(x,y,viewOrientationFactor * zExtLine);
}
}
else if ( issketchinvalid ) {
color[i] = drawingParameters.InvalidSketchColor;
for (int k=j; j<k+indexes; j++) {
verts[j].getValue(x,y,z);
verts[j] = SbVec3f(x,y,viewOrientationFactor * zNormLine);
}
}
else if (isConstructionGeom(GeoId)) {
if(isInternalAlignedGeom(GeoId)) {
if(constrainedElement)
color[i] = drawingParameters.FullyConstraintInternalAlignmentColor;
else
color[i] = drawingParameters.InternalAlignedGeoColor;
}
else {
if(constrainedElement)
color[i] = drawingParameters.FullyConstraintConstructionElementColor;
else
color[i] = drawingParameters.CurveDraftColor;
}
for (int k=j; j<k+indexes; j++) {
verts[j].getValue(x,y,z);
verts[j] = SbVec3f(x,y,viewOrientationFactor * zConstrLine);
}
}
else if (ViewProviderSketchCoinAttorney::isSketchFullyConstrained(viewProvider)) {
color[i] = drawingParameters.FullyConstrainedColor;
for (int k=j; j<k+indexes; j++) {
verts[j].getValue(x,y,z);
verts[j] = SbVec3f(x,y,viewOrientationFactor * zNormLine);
}
}
else if (isFullyConstraintElement(GeoId)) {
color[i] = drawingParameters.FullyConstraintElementColor;
for (int k=j; j<k+indexes; j++) {
verts[j].getValue(x,y,z);
verts[j] = SbVec3f(x,y,viewOrientationFactor * zNormLine);
}
}
else {
color[i] = drawingParameters.CurveColor;
for (int k=j; j<k+indexes; j++) {
verts[j].getValue(x,y,z);
verts[j] = SbVec3f(x,y,viewOrientationFactor * zNormLine);
}
}
}
// colors of the cross
if ( l == 0 ) { // only in layer 0
if (ViewProviderSketchCoinAttorney::isCurveSelected(viewProvider, Sketcher::GeoEnum::HAxis)) {
crosscolor[0] = drawingParameters.SelectColor;
}
else if (preselectcross == 1) { // cross only in layer 0
crosscolor[0] = drawingParameters.PreselectColor;
}
else {
crosscolor[0] = drawingParameters.CrossColorH;
}
if (ViewProviderSketchCoinAttorney::isCurveSelected(viewProvider, Sketcher::GeoEnum::VAxis)) {
crosscolor[1] = drawingParameters.SelectColor;
}
else if (preselectcross == 2) {
crosscolor[1] = drawingParameters.PreselectColor;
}
else {
crosscolor[1] = drawingParameters.CrossColorV;
}
}
// end editing
editModeScenegraphNodes.CurvesMaterials[l]->diffuseColor.finishEditing();
editModeScenegraphNodes.PointsMaterials[l]->diffuseColor.finishEditing();
editModeScenegraphNodes.CurvesCoordinate[l]->point.finishEditing();
editModeScenegraphNodes.CurveSet[l]->numVertices.finishEditing();
}
editModeScenegraphNodes.RootCrossMaterials->diffuseColor.finishEditing();
}
void EditModeGeometryCoinManager::updateGeometryLayersConfiguration()
{
// Several cases:
// 1) The number of layers have changed
// 2) The number of layers is the same, but the configuration needs to be updated
// TODO: Quite some room for improvement here:
geometryLayerParameters.setCoinLayerCount(viewProvider.VisualLayerList.getSize());
emptyGeometryRootNodes();
createEditModePointInventorNodes();
createEditModeCurveInventorNodes();
}
auto concat (std::string string, int i)
{
return string+std::to_string(i);
};
void EditModeGeometryCoinManager::createEditModeInventorNodes()
{
createGeometryRootNodes();
geometryLayerParameters.setCoinLayerCount(viewProvider.VisualLayerList.getSize());
createEditModePointInventorNodes();
createEditModeCurveInventorNodes();
}
void EditModeGeometryCoinManager::createGeometryRootNodes()
{
// stuff for the points ++++++++++++++++++++++++++++++++++++++
editModeScenegraphNodes.PointsGroup = new SmSwitchboard;
editModeScenegraphNodes.EditRoot->addChild(editModeScenegraphNodes.PointsGroup);
// stuff for the Curves +++++++++++++++++++++++++++++++++++++++
editModeScenegraphNodes.CurvesGroup = new SmSwitchboard;
editModeScenegraphNodes.EditRoot->addChild(editModeScenegraphNodes.CurvesGroup);
}
void EditModeGeometryCoinManager::emptyGeometryRootNodes()
{
Gui::coinRemoveAllChildren(editModeScenegraphNodes.PointsGroup);
Gui::coinRemoveAllChildren(editModeScenegraphNodes.CurvesGroup);
}
void EditModeGeometryCoinManager::createEditModePointInventorNodes()
{
for(int i=0; i < geometryLayerParameters.getCoinLayerCount(); i++) {
SoSeparator * sep = new SoSeparator;
sep->ref();
auto somaterial = new SoMaterial;
editModeScenegraphNodes.PointsMaterials.push_back(somaterial);
editModeScenegraphNodes.PointsMaterials[i]->setName(concat("PointsMaterials_",i).c_str());
sep->addChild(editModeScenegraphNodes.PointsMaterials[i]);
SoMaterialBinding *MtlBind = new SoMaterialBinding;
MtlBind->setName(concat("PointsMaterialBinding",i).c_str());
MtlBind->value = SoMaterialBinding::PER_VERTEX;
sep->addChild(MtlBind);
auto coords = new SoCoordinate3;
editModeScenegraphNodes.PointsCoordinate.push_back(coords);
editModeScenegraphNodes.PointsCoordinate[i]->setName(concat("PointsCoordinate",i).c_str());
sep->addChild(editModeScenegraphNodes.PointsCoordinate[i]);
auto drawstyle = new SoDrawStyle;
editModeScenegraphNodes.PointsDrawStyle.push_back(drawstyle);
editModeScenegraphNodes.PointsDrawStyle[i]->setName(concat("PointsDrawStyle",i).c_str());
editModeScenegraphNodes.PointsDrawStyle[i]->pointSize = 8 * drawingParameters.pixelScalingFactor;
sep->addChild(editModeScenegraphNodes.PointsDrawStyle[i]);
auto pointset = new SoMarkerSet;
editModeScenegraphNodes.PointSet.push_back(pointset);
editModeScenegraphNodes.PointSet[i]->setName(concat("PointSet",i).c_str());
editModeScenegraphNodes.PointSet[i]->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_FILLED", drawingParameters.markerSize);
sep->addChild(editModeScenegraphNodes.PointSet[i]);
editModeScenegraphNodes.PointsGroup->addChild(sep);
sep->unref();
}
}
void EditModeGeometryCoinManager::createEditModeCurveInventorNodes()
{
auto layersconfigurations = viewProvider.VisualLayerList.getValue();
for(int i=0; i < geometryLayerParameters.getCoinLayerCount(); i++) {
SoSeparator * sep = new SoSeparator;
sep->ref();
auto somaterial = new SoMaterial;
editModeScenegraphNodes.CurvesMaterials.push_back(somaterial);
editModeScenegraphNodes.CurvesMaterials[i]->setName(concat("CurvesMaterials",i).c_str());
sep->addChild(editModeScenegraphNodes.CurvesMaterials[i]);
auto MtlBind = new SoMaterialBinding;
MtlBind->setName(concat("CurvesMaterialsBinding",i).c_str());
MtlBind->value = SoMaterialBinding::PER_FACE;
sep->addChild(MtlBind);
auto coords = new SoCoordinate3;
editModeScenegraphNodes.CurvesCoordinate.push_back(coords);
editModeScenegraphNodes.CurvesCoordinate[i]->setName(concat("CurvesCoordinate",i).c_str());
sep->addChild(editModeScenegraphNodes.CurvesCoordinate[i]);
auto drawstyle = new SoDrawStyle;
editModeScenegraphNodes.CurvesDrawStyle.push_back(drawstyle);
editModeScenegraphNodes.CurvesDrawStyle[i]->setName(concat("CurvesDrawStyle",i).c_str());
editModeScenegraphNodes.CurvesDrawStyle[i]->lineWidth = layersconfigurations[i].getLineWidth() * drawingParameters.pixelScalingFactor;
editModeScenegraphNodes.CurvesDrawStyle[i]->linePattern = layersconfigurations[i].getLinePattern();
editModeScenegraphNodes.CurvesDrawStyle[i]->linePatternScaleFactor = 5;
sep->addChild(editModeScenegraphNodes.CurvesDrawStyle[i]);
auto solineset = new SoLineSet;
editModeScenegraphNodes.CurveSet.push_back(solineset);
editModeScenegraphNodes.CurveSet[i]->setName(concat("CurvesLineSet",i).c_str());
sep->addChild(editModeScenegraphNodes.CurveSet[i]);
editModeScenegraphNodes.CurvesGroup->addChild(sep);
sep->unref();
}
}