Gui: refactor bounding box selection style
Previously, box style selection is rendered using customized SoBoxSelectionRenderAction, which does not support selection context, i.e. it does not work with Link. This patch implements context aware bound box rendering inside SoFCSelectionRoot, SoFCSelection and SoFCPathAnnotation (for always on top rendering). The box rendering in SoBoxSelectionRenderAction is disabled on construction. Box style selection can be enabled for individual object through property SelectionStyle (moved from ViewProviderGeometryObject to ViewProviderDocumentObject), or globally through Parameter BaseApp/Preferences/View/ShowSelectionBoundingBox. In addition, the parameter BaseApp/Preferences/View/UseNewSelection is used to override selection model reported from ViewProvider::useNewSelectionModel(). The reason being that, the same parameter is already used to toggle selection model inside SoFCSelection. This avoids inconsistency of selection model choice between view provider and the SoFCSelection node inside. Note that if the parameter 'UseNewSelection' is set to false, those view providers that choose old selection model will not work with Link.
This commit is contained in:
@@ -315,7 +315,7 @@ ViewProviderMesh::ViewProviderMesh() : pcOpenEdge(0)
|
||||
}
|
||||
|
||||
if (hGrp->GetBool("ShowBoundingBox", false))
|
||||
pcHighlight->style = Gui::SoFCSelection::BOX;
|
||||
SelectionStyle.setValue(1);
|
||||
|
||||
Coloring.setStatus(App::Property::Hidden, true);
|
||||
}
|
||||
@@ -370,6 +370,10 @@ void ViewProviderMesh::onChanged(const App::Property* prop)
|
||||
else if (prop == &Coloring) {
|
||||
tryColorPerVertexOrFace(Coloring.getValue());
|
||||
}
|
||||
else if (prop == &SelectionStyle) {
|
||||
pcHighlight->style = SelectionStyle.getValue()
|
||||
?Gui::SoFCSelection::BOX:Gui::SoFCSelection::EMISSIVE;
|
||||
}
|
||||
else {
|
||||
// Set the inverse color for open edges
|
||||
if (prop == &ShapeColor) {
|
||||
|
||||
@@ -164,6 +164,41 @@ void SoBrepEdgeSet::GLRenderBelowPath(SoGLRenderAction * action)
|
||||
inherited::GLRenderBelowPath(action);
|
||||
}
|
||||
|
||||
void SoBrepEdgeSet::getBoundingBox(SoGetBoundingBoxAction * action) {
|
||||
|
||||
SelContextPtr ctx2 = Gui::SoFCSelectionRoot::getSecondaryActionContext<SelContext>(action,this);
|
||||
if(!ctx2 || (ctx2->sl.size()==1 && ctx2->sl[0]<0)) {
|
||||
inherited::getBoundingBox(action);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx2->sl.empty())
|
||||
return;
|
||||
|
||||
auto state = action->getState();
|
||||
auto coords = SoCoordinateElement::getInstance(state);
|
||||
const SbVec3f *coords3d = coords->getArrayPtr3();
|
||||
|
||||
if(!validIndexes(coords,ctx2->sl))
|
||||
return;
|
||||
|
||||
SbBox3f bbox;
|
||||
|
||||
int32_t i;
|
||||
const int32_t *cindices = &ctx2->sl[0];
|
||||
const int32_t *end = cindices + ctx2->sl.size();
|
||||
while (cindices < end) {
|
||||
bbox.extendBy(coords3d[*cindices++]);
|
||||
i = (cindices < end) ? *cindices++ : -1;
|
||||
while (i >= 0) {
|
||||
bbox.extendBy(coords3d[i]);
|
||||
i = cindices < end ? *cindices++ : -1;
|
||||
}
|
||||
}
|
||||
if(!bbox.isEmpty())
|
||||
action->extendBy(bbox);
|
||||
}
|
||||
|
||||
void SoBrepEdgeSet::renderShape(const SoGLCoordinateElement * const coords,
|
||||
const int32_t *cindices, int numindices)
|
||||
{
|
||||
|
||||
@@ -60,6 +60,9 @@ protected:
|
||||
const SoPrimitiveVertex *v1,
|
||||
const SoPrimitiveVertex *v2,
|
||||
SoPickedPoint *pp);
|
||||
|
||||
virtual void getBoundingBox(SoGetBoundingBoxAction * action);
|
||||
|
||||
private:
|
||||
struct SelContext;
|
||||
typedef std::shared_ptr<SelContext> SelContextPtr;
|
||||
|
||||
@@ -890,6 +890,53 @@ void SoBrepFaceSet::GLRenderBelowPath(SoGLRenderAction * action)
|
||||
inherited::GLRenderBelowPath(action);
|
||||
}
|
||||
|
||||
void SoBrepFaceSet::getBoundingBox(SoGetBoundingBoxAction * action) {
|
||||
|
||||
if (this->coordIndex.getNum() < 3)
|
||||
return;
|
||||
|
||||
SelContextPtr ctx2 = Gui::SoFCSelectionRoot::getSecondaryActionContext<SelContext>(action,this);
|
||||
if(!ctx2 || ctx2->isSelectAll()) {
|
||||
inherited::getBoundingBox(action);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx2->selectionIndex.empty())
|
||||
return;
|
||||
|
||||
auto state = action->getState();
|
||||
auto coords = SoCoordinateElement::getInstance(state);
|
||||
const SbVec3f *coords3d = static_cast<const SoGLCoordinateElement*>(coords)->getArrayPtr3();
|
||||
const int32_t *cindices = this->coordIndex.getValues(0);
|
||||
const int32_t *pindices = this->partIndex.getValues(0);
|
||||
int numparts = this->partIndex.getNum();
|
||||
|
||||
SbBox3f bbox;
|
||||
for(auto id : ctx2->selectionIndex) {
|
||||
if (id<0 || id >= numparts)
|
||||
break;
|
||||
// coords
|
||||
int length=0;
|
||||
int start=0;
|
||||
length = (int)pindices[id]*4;
|
||||
for (int j=0;j<id;j++)
|
||||
start+=(int)pindices[j];
|
||||
start *= 4;
|
||||
|
||||
auto viptr = &cindices[start];
|
||||
auto viendptr = viptr + length;
|
||||
while (viptr + 2 < viendptr) {
|
||||
bbox.extendBy(coords3d[*viptr++]);
|
||||
bbox.extendBy(coords3d[*viptr++]);
|
||||
bbox.extendBy(coords3d[*viptr++]);
|
||||
++viptr;
|
||||
}
|
||||
}
|
||||
|
||||
if(!bbox.isEmpty())
|
||||
action->extendBy(bbox);
|
||||
}
|
||||
|
||||
// this macro actually makes the code below more readable :-)
|
||||
#define DO_VERTEX(idx) \
|
||||
if (mbind == PER_VERTEX) { \
|
||||
|
||||
@@ -98,6 +98,7 @@ protected:
|
||||
const SoPrimitiveVertex * v3,
|
||||
SoPickedPoint * pp);
|
||||
virtual void generatePrimitives(SoAction * action);
|
||||
virtual void getBoundingBox(SoGetBoundingBoxAction * action);
|
||||
|
||||
private:
|
||||
enum Binding {
|
||||
|
||||
@@ -154,6 +154,33 @@ void SoBrepPointSet::GLRenderBelowPath(SoGLRenderAction * action)
|
||||
inherited::GLRenderBelowPath(action);
|
||||
}
|
||||
|
||||
void SoBrepPointSet::getBoundingBox(SoGetBoundingBoxAction * action) {
|
||||
|
||||
SelContextPtr ctx2 = Gui::SoFCSelectionRoot::getSecondaryActionContext<SelContext>(action,this);
|
||||
if(!ctx2 || ctx2->isSelectAll()) {
|
||||
inherited::getBoundingBox(action);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx2->selectionIndex.empty())
|
||||
return;
|
||||
|
||||
auto state = action->getState();
|
||||
auto coords = SoCoordinateElement::getInstance(state);
|
||||
const SbVec3f *coords3d = coords->getArrayPtr3();
|
||||
int numverts = coords->getNum();
|
||||
int startIndex = this->startIndex.getValue();
|
||||
|
||||
SbBox3f bbox;
|
||||
for(auto idx : ctx2->selectionIndex) {
|
||||
if(idx >= startIndex && idx < numverts)
|
||||
bbox.extendBy(coords3d[idx]);
|
||||
}
|
||||
|
||||
if(!bbox.isEmpty())
|
||||
action->extendBy(bbox);
|
||||
}
|
||||
|
||||
void SoBrepPointSet::renderHighlight(SoGLRenderAction *action, SelContextPtr ctx)
|
||||
{
|
||||
if(!ctx || ctx->highlightIndex<0)
|
||||
|
||||
@@ -56,6 +56,8 @@ protected:
|
||||
virtual void GLRenderBelowPath(SoGLRenderAction * action);
|
||||
virtual void doAction(SoAction* action);
|
||||
|
||||
virtual void getBoundingBox(SoGetBoundingBoxAction * action);
|
||||
|
||||
private:
|
||||
typedef Gui::SoFCSelectionContext SelContext;
|
||||
typedef Gui::SoFCSelectionContextPtr SelContextPtr;
|
||||
|
||||
@@ -493,6 +493,12 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat)
|
||||
pcPointsRoot->renderCaching =
|
||||
wireframe->renderCaching = SoSeparator::OFF;
|
||||
|
||||
pcNormalRoot->boundingBoxCaching =
|
||||
pcFlatRoot->boundingBoxCaching =
|
||||
pcWireframeRoot->boundingBoxCaching =
|
||||
pcPointsRoot->boundingBoxCaching =
|
||||
wireframe->boundingBoxCaching = SoSeparator::OFF;
|
||||
|
||||
// enable two-side rendering
|
||||
pShapeHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
|
||||
pShapeHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
|
||||
|
||||
Reference in New Issue
Block a user