PartDesign: Add support for preview for transforms
This commit is contained in:
@@ -137,13 +137,46 @@ void ViewProviderPreviewExtension::extensionAttach(App::DocumentObject* document
|
||||
{
|
||||
ViewProviderExtension::extensionAttach(documentObject);
|
||||
|
||||
pcPreviewRoot = new SoSeparator;
|
||||
pcPreviewShape = new SoPreviewShape;
|
||||
|
||||
pcPreviewRoot = new SoSeparator;
|
||||
pcPreviewRoot->addChild(pcPreviewShape);
|
||||
|
||||
updatePreviewShape();
|
||||
attachPreview();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void ViewProviderPreviewExtension::extensionBeforeDelete()
|
||||
{
|
||||
ViewProviderExtension::extensionBeforeDelete();
|
||||
|
||||
showPreview(false);
|
||||
}
|
||||
|
||||
void ViewProviderPreviewExtension::showPreview(bool enable)
|
||||
{
|
||||
auto feature = getExtendedViewProvider()->getObject<Part::Feature>();
|
||||
if (!feature) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto previewExtension = feature->getExtensionByType<Part::PreviewExtension>(true);
|
||||
if (!previewExtension) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isPreviewEnabled = enable;
|
||||
|
||||
auto annotationRoot = getExtendedViewProvider()->getAnnotation();
|
||||
if (enable) {
|
||||
previewExtension->updatePreview();
|
||||
|
||||
if (annotationRoot->findChild(pcPreviewRoot) < 0) {
|
||||
annotationRoot->addChild(pcPreviewRoot);
|
||||
}
|
||||
} else {
|
||||
annotationRoot->removeChild(pcPreviewRoot);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewProviderPreviewExtension::extensionOnChanged(const App::Property* prop)
|
||||
{
|
||||
if (prop == &PreviewColor) {
|
||||
@@ -153,39 +186,68 @@ void ViewProviderPreviewExtension::extensionOnChanged(const App::Property* prop)
|
||||
ViewProviderExtension::extensionOnChanged(prop);
|
||||
}
|
||||
|
||||
void ViewProviderPreviewExtension::updatePreviewShape()
|
||||
void ViewProviderPreviewExtension::attachPreview()
|
||||
{
|
||||
pcPreviewRoot->addChild(pcPreviewShape);
|
||||
}
|
||||
|
||||
void ViewProviderPreviewExtension::updatePreview()
|
||||
{
|
||||
updatePreviewShape(getPreviewShape(), pcPreviewShape);
|
||||
}
|
||||
|
||||
void ViewProviderPreviewExtension::updatePreviewShape(Part::TopoShape shape,
|
||||
SoPreviewShape* preview)
|
||||
{
|
||||
if (shape.isNull() || preview == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto vp = freecad_cast<ViewProviderPartExt*>(getExtendedViewProvider());
|
||||
|
||||
if (!vp) {
|
||||
return;
|
||||
}
|
||||
|
||||
ViewProviderPartExt::setupCoinGeometry(getPreviewShape().getShape(),
|
||||
pcPreviewShape->coords,
|
||||
pcPreviewShape->faceset,
|
||||
pcPreviewShape->norm,
|
||||
pcPreviewShape->lineset,
|
||||
pcPreviewShape->nodeset,
|
||||
vp->Deviation.getValue(),
|
||||
vp->AngularDeflection.getValue(),
|
||||
false);
|
||||
const auto updatePreviewShape = [vp](SoPreviewShape* preview, Part::TopoShape shape) {
|
||||
ViewProviderPartExt::setupCoinGeometry(shape.getShape(),
|
||||
preview->coords,
|
||||
preview->faceset,
|
||||
preview->norm,
|
||||
preview->lineset,
|
||||
preview->nodeset,
|
||||
vp->Deviation.getValue(),
|
||||
vp->AngularDeflection.getValue(),
|
||||
false);
|
||||
};
|
||||
|
||||
try {
|
||||
updatePreviewShape(preview, shape);
|
||||
} catch (Standard_Failure& e) {
|
||||
Base::Console().userTranslatedNotification(
|
||||
tr("Failure while rendering preview: %1. That usually indicates an error with model.")
|
||||
.arg(QString::fromUtf8(e.GetMessageString()))
|
||||
.toUtf8());
|
||||
|
||||
updatePreviewShape(preview, {});
|
||||
}
|
||||
|
||||
// For some reason line patterns are not rendered correctly if material binding is set to
|
||||
// anything other than PER_FACE. PER_FACE material binding seems to require materialIndex per
|
||||
// each distinct edge. Until that is fixed, this code forces each edge to use the first material.
|
||||
unsigned lineCoordsCount = pcPreviewShape->lineset->coordIndex.getNum();
|
||||
// each distinct edge. Until that is fixed, this code forces each edge to use the first
|
||||
// material.
|
||||
unsigned lineCoordsCount = preview->lineset->coordIndex.getNum();
|
||||
unsigned lineCount = 1;
|
||||
|
||||
for (unsigned i = 0; i < lineCoordsCount; ++i) {
|
||||
if (pcPreviewShape->lineset->coordIndex[i] < 0) {
|
||||
if (preview->lineset->coordIndex[i] < 0) {
|
||||
lineCount++;
|
||||
}
|
||||
}
|
||||
|
||||
pcPreviewShape->lineset->materialIndex.setNum(lineCount);
|
||||
preview->lineset->materialIndex.setNum(lineCount);
|
||||
for (unsigned i = 0; i < lineCount; ++i) {
|
||||
pcPreviewShape->lineset->materialIndex.set1Value(i, 0);
|
||||
preview->lineset->materialIndex.set1Value(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <Gui/ViewProviderExtension.h>
|
||||
#include <Gui/ViewProviderExtensionPython.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/PartDesign/App/Feature.h>
|
||||
|
||||
namespace PartGui {
|
||||
|
||||
@@ -92,8 +93,12 @@ public:
|
||||
protected:
|
||||
void extensionOnChanged(const App::Property* prop) override;
|
||||
|
||||
/// attaches preview to the scene graph
|
||||
virtual void attachPreview();
|
||||
/// updates preview
|
||||
virtual void updatePreview();
|
||||
/// updates geometry of the preview shape
|
||||
void updatePreviewShape();
|
||||
void updatePreviewShape(Part::TopoShape shape, SoPreviewShape* preview);
|
||||
|
||||
Gui::CoinPtr<SoSeparator> pcPreviewRoot;
|
||||
Gui::CoinPtr<SoPreviewShape> pcPreviewShape;
|
||||
|
||||
@@ -50,11 +50,6 @@ public:
|
||||
}
|
||||
//@}
|
||||
|
||||
std::vector<App::DocumentObject*> getOriginals() const
|
||||
{
|
||||
return Originals.getValues();
|
||||
}
|
||||
|
||||
/** Create transformations
|
||||
* Returns a list containing the product of all transformations of the subfeatures given
|
||||
* by the Transformations property. Subfeatures can be Mirrored, LinearPattern, PolarPattern and
|
||||
|
||||
@@ -115,9 +115,33 @@ Part::Feature* Transformed::getBaseObject(bool silent) const
|
||||
return rv;
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> Transformed::getOriginals() const
|
||||
{
|
||||
auto const mode = static_cast<Mode>(TransformMode.getValue());
|
||||
|
||||
if (mode == Mode::TransformBody) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<DocumentObject*> originals = Originals.getValues();
|
||||
|
||||
const auto isSuppressed = [](const DocumentObject* obj) {
|
||||
auto feature = freecad_cast<Feature*>(obj);
|
||||
|
||||
return feature != nullptr && feature->Suppressed.getValue();
|
||||
};
|
||||
|
||||
// Remove suppressed features from the list so the transformations behave as if they are not
|
||||
// there
|
||||
auto [first, last] = std::ranges::remove_if(originals, isSuppressed);
|
||||
originals.erase(first, last);
|
||||
|
||||
return originals;
|
||||
}
|
||||
|
||||
App::DocumentObject* Transformed::getSketchObject() const
|
||||
{
|
||||
std::vector<DocumentObject*> originals = Originals.getValues();
|
||||
std::vector<DocumentObject*> originals = getOriginals();
|
||||
DocumentObject const* firstOriginal = !originals.empty() ? originals.front() : nullptr;
|
||||
|
||||
if (auto feature = freecad_cast<PartDesign::ProfileBased*>(firstOriginal)) {
|
||||
@@ -198,6 +222,15 @@ short Transformed::mustExecute() const
|
||||
}
|
||||
return PartDesign::Feature::mustExecute();
|
||||
}
|
||||
void Transformed::onChanged(const App::Property* prop)
|
||||
{
|
||||
if (prop == &TransformMode) {
|
||||
auto const mode = static_cast<Mode>(TransformMode.getValue());
|
||||
Originals.setStatus(App::Property::Status::Hidden, mode == Mode::TransformBody);
|
||||
}
|
||||
|
||||
FeatureRefine::onChanged(prop);
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn* Transformed::execute()
|
||||
{
|
||||
@@ -205,30 +238,16 @@ App::DocumentObjectExecReturn* Transformed::execute()
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> originals;
|
||||
auto const mode = static_cast<Mode>(TransformMode.getValue());
|
||||
if (mode == Mode::TransformBody) {
|
||||
Originals.setStatus(App::Property::Status::Hidden, true);
|
||||
} else {
|
||||
Originals.setStatus(App::Property::Status::Hidden, false);
|
||||
originals = Originals.getValues();
|
||||
}
|
||||
// Remove suppressed features from the list so the transformations behave as if they are not
|
||||
// there
|
||||
auto eraseIter =
|
||||
std::remove_if(originals.begin(), originals.end(), [](App::DocumentObject const* obj) {
|
||||
auto feature = freecad_cast<PartDesign::Feature*>(obj);
|
||||
return feature != nullptr && feature->Suppressed.getValue();
|
||||
});
|
||||
originals.erase(eraseIter, originals.end());
|
||||
|
||||
std::vector<DocumentObject*> originals = getOriginals();
|
||||
|
||||
if (mode == Mode::TransformToolShapes && originals.empty()) {
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
if (!this->BaseFeature.getValue()) {
|
||||
auto body = getFeatureBody();
|
||||
if (body) {
|
||||
if (auto body = getFeatureBody()) {
|
||||
body->setBaseProperty(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +53,7 @@ public:
|
||||
/** The features to be transformed
|
||||
*/
|
||||
App::PropertyLinkList Originals;
|
||||
|
||||
App::PropertyEnumeration TransformMode;
|
||||
|
||||
App::PropertyBool Refine;
|
||||
|
||||
/**
|
||||
@@ -67,6 +65,8 @@ public:
|
||||
*/
|
||||
Part::Feature* getBaseObject(bool silent = false) const override;
|
||||
|
||||
virtual std::vector<App::DocumentObject*> getOriginals() const;
|
||||
|
||||
/// Return the sketch of the first original
|
||||
App::DocumentObject* getSketchObject() const;
|
||||
|
||||
@@ -94,6 +94,8 @@ public:
|
||||
short mustExecute() const override;
|
||||
//@}
|
||||
|
||||
void onChanged(const App::Property* prop) override;
|
||||
|
||||
/** returns the compound of the shapes that were rejected during the last execute
|
||||
* because they did not overlap with the support
|
||||
*/
|
||||
|
||||
@@ -569,7 +569,6 @@ void TaskTransformedParameters::exitSelectionMode()
|
||||
clearButtons();
|
||||
selectionMode = SelectionMode::None;
|
||||
Gui::Selection().rmvSelectionGate();
|
||||
showObject();
|
||||
}
|
||||
catch (Base::Exception& exc) {
|
||||
exc.reportException();
|
||||
|
||||
@@ -203,7 +203,11 @@ void ViewProvider::unsetEdit(int ModNum)
|
||||
void ViewProvider::updateData(const App::Property* prop)
|
||||
{
|
||||
if (strcmp(prop->getName(), "PreviewShape") == 0) {
|
||||
updatePreviewShape();
|
||||
updatePreview();
|
||||
} else if (auto* previewExtension = getObject()->getExtensionByType<Part::PreviewExtension>(true)) {
|
||||
if (!previewExtension->isPreviewFresh() && isEditing()) {
|
||||
previewExtension->updatePreview();
|
||||
}
|
||||
}
|
||||
|
||||
inherited::updateData(prop);
|
||||
@@ -284,11 +288,11 @@ void ViewProvider::setTipIcon(bool onoff) {
|
||||
signalChangeIcon();
|
||||
}
|
||||
|
||||
QIcon ViewProvider::mergeColorfulOverlayIcons (const QIcon & orig) const
|
||||
QIcon ViewProvider::mergeColorfulOverlayIcons(const QIcon& orig) const
|
||||
{
|
||||
QIcon mergedicon = orig;
|
||||
|
||||
if(isSetTipIcon) {
|
||||
if (isSetTipIcon) {
|
||||
static QPixmap px(Gui::BitmapFactory().pixmapFromSvg("PartDesign_Overlay_Tip", QSize(10, 10)));
|
||||
mergedicon = Gui::BitmapFactoryInst::mergePixmap(mergedicon, px, Gui::BitmapFactoryInst::BottomRight);
|
||||
}
|
||||
|
||||
@@ -38,13 +38,12 @@ public:
|
||||
sPixmap = "PartDesign_Mirrored.svg";
|
||||
}
|
||||
|
||||
const std::string & featureName() const override;
|
||||
const std::string& featureName() const override;
|
||||
void setupContextMenu(QMenu*, QObject*, const char*) override;
|
||||
|
||||
protected:
|
||||
/// Returns a newly create dialog for the part to be placed in the task view
|
||||
/// Returns a newly created dialog for the part to be placed in the task view
|
||||
TaskDlgFeatureParameters *getEditDialog() override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -26,23 +26,9 @@
|
||||
#ifndef _PreComp_
|
||||
# include <Bnd_Box.hxx>
|
||||
# include <BRep_Tool.hxx>
|
||||
# include <BRepBndLib.hxx>
|
||||
# include <BRepMesh_IncrementalMesh.hxx>
|
||||
# include <Poly_Triangulation.hxx>
|
||||
# include <Standard_Version.hxx>
|
||||
# include <TopExp_Explorer.hxx>
|
||||
# include <TopoDS.hxx>
|
||||
# include <Inventor/nodes/SoCoordinate3.h>
|
||||
# include <Inventor/nodes/SoDrawStyle.h>
|
||||
# include <Inventor/nodes/SoIndexedFaceSet.h>
|
||||
# include <Inventor/nodes/SoMaterial.h>
|
||||
# include <Inventor/nodes/SoMultipleCopy.h>
|
||||
# include <Inventor/nodes/SoNormal.h>
|
||||
# include <Inventor/nodes/SoPickStyle.h>
|
||||
# include <Inventor/nodes/SoSeparator.h>
|
||||
# include <Inventor/nodes/SoShapeHints.h>
|
||||
# include <Inventor/nodes/SoTransparencyType.h>
|
||||
# include <QAction>
|
||||
# include <QMenu>
|
||||
#endif
|
||||
|
||||
@@ -56,9 +42,11 @@
|
||||
#include "ViewProviderTransformed.h"
|
||||
#include "TaskTransformedParameters.h"
|
||||
|
||||
#include <Inventor/nodes/SoTransform.h>
|
||||
|
||||
using namespace PartDesignGui;
|
||||
|
||||
PROPERTY_SOURCE(PartDesignGui::ViewProviderTransformed,PartDesignGui::ViewProvider)
|
||||
PROPERTY_SOURCE(PartDesignGui::ViewProviderTransformed, PartDesignGui::ViewProvider)
|
||||
|
||||
const std::string & ViewProviderTransformed::featureName() const
|
||||
{
|
||||
@@ -68,99 +56,105 @@ const std::string & ViewProviderTransformed::featureName() const
|
||||
|
||||
std::string ViewProviderTransformed::featureIcon() const
|
||||
{
|
||||
return std::string("PartDesign_") + featureName();
|
||||
return fmt::format("PartDesign_{}", featureName());
|
||||
}
|
||||
|
||||
void ViewProviderTransformed::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
|
||||
{
|
||||
QString text = QString::fromStdString(getObject()->Label.getStrValue());
|
||||
addDefaultAction(menu, QObject::tr("Edit %1").arg(text));
|
||||
PartDesignGui::ViewProvider::setupContextMenu(menu, receiver, member);
|
||||
|
||||
ViewProvider::setupContextMenu(menu, receiver, member);
|
||||
}
|
||||
|
||||
Gui::ViewProvider *ViewProviderTransformed::startEditing(int ModNum) {
|
||||
PartDesign::Transformed* pcTransformed = getObject<PartDesign::Transformed>();
|
||||
if(!pcTransformed->Originals.getSize()) {
|
||||
for(auto obj : pcTransformed->getInList()) {
|
||||
if(obj->isDerivedFrom<PartDesign::MultiTransform>()) {
|
||||
auto vp = Gui::Application::Instance->getViewProvider(obj);
|
||||
if(vp)
|
||||
return vp->startEditing(ModNum);
|
||||
return nullptr;
|
||||
auto* pcTransformed = getObject<PartDesign::Transformed>();
|
||||
|
||||
if (!pcTransformed->Originals.getSize()) {
|
||||
for (auto obj : pcTransformed->getInList()) {
|
||||
if (!obj->isDerivedFrom<PartDesign::MultiTransform>()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto vp = Gui::Application::Instance->getViewProvider(obj)) {
|
||||
return vp->startEditing(ModNum);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return ViewProvider::startEditing(ModNum);
|
||||
}
|
||||
|
||||
bool ViewProviderTransformed::setEdit(int ModNum)
|
||||
{
|
||||
pcRejectedRoot = new SoSeparator();
|
||||
pcRejectedRoot->ref();
|
||||
|
||||
SoPickStyle* rejectedPickStyle = new SoPickStyle();
|
||||
rejectedPickStyle->style = SoPickStyle::UNPICKABLE;
|
||||
|
||||
SoShapeHints* rejectedHints = new SoShapeHints();
|
||||
rejectedHints->vertexOrdering = SoShapeHints::UNKNOWN_ORDERING;
|
||||
rejectedHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
|
||||
|
||||
SoMaterialBinding* rejectedBind = new SoMaterialBinding();
|
||||
|
||||
SoTransparencyType* rejectedTransparencyType = new SoTransparencyType();
|
||||
rejectedTransparencyType->value.setValue(SoGLRenderAction::BLEND);
|
||||
|
||||
SoMaterial* rejectedMaterial = new SoMaterial();
|
||||
rejectedMaterial->diffuseColor.set1Value(0,SbColor(1.f,0.f,0.f));
|
||||
rejectedMaterial->transparency.setValue(0.6f);
|
||||
|
||||
SoDrawStyle* rejectedFaceStyle = new SoDrawStyle();
|
||||
rejectedFaceStyle->style = SoDrawStyle::FILLED;
|
||||
|
||||
SoNormalBinding* rejectedNormb = new SoNormalBinding();
|
||||
rejectedNormb->value = SoNormalBinding::PER_VERTEX_INDEXED;
|
||||
|
||||
// just faces with no edges or points
|
||||
pcRejectedRoot->addChild(rejectedPickStyle);
|
||||
pcRejectedRoot->addChild(rejectedTransparencyType);
|
||||
pcRejectedRoot->addChild(rejectedBind);
|
||||
pcRejectedRoot->addChild(rejectedMaterial);
|
||||
pcRejectedRoot->addChild(rejectedHints);
|
||||
pcRejectedRoot->addChild(rejectedFaceStyle);
|
||||
pcRejectedRoot->addChild(rejectedNormb); // NOTE: The code relies on the last child added here being index 6
|
||||
pcRoot->addChild(pcRejectedRoot);
|
||||
|
||||
recomputeFeature(false);
|
||||
|
||||
return ViewProvider::setEdit(ModNum);
|
||||
}
|
||||
|
||||
void ViewProviderTransformed::unsetEdit(int ModNum)
|
||||
void ViewProviderTransformed::attachPreview()
|
||||
{
|
||||
ViewProvider::unsetEdit(ModNum);
|
||||
}
|
||||
|
||||
while (pcRejectedRoot->getNumChildren() > 7) {
|
||||
SoSeparator* sep = static_cast<SoSeparator*>(pcRejectedRoot->getChild(7));
|
||||
SoMultipleCopy* rejectedTrfms = static_cast<SoMultipleCopy*>(sep->getChild(2));
|
||||
Gui::coinRemoveAllChildren(rejectedTrfms);
|
||||
sep->removeChild(1);
|
||||
sep->removeChild(0);
|
||||
pcRejectedRoot ->removeChild(7);
|
||||
void ViewProviderTransformed::updatePreview()
|
||||
{
|
||||
try {
|
||||
if (auto feature = getObject<PartDesign::Transformed>()) {
|
||||
auto originals = feature->getOriginals();
|
||||
auto transforms = feature->getTransformations(originals);
|
||||
|
||||
if (transforms.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
transforms.pop_front();
|
||||
|
||||
Gui::coinRemoveAllChildren(pcPreviewRoot);
|
||||
|
||||
for (const auto& transform : transforms) {
|
||||
Base::Matrix4D transformMatrix;
|
||||
Part::TopoShape::convertToMatrix(transform, transformMatrix);
|
||||
|
||||
auto sep = new SoSeparator;
|
||||
|
||||
auto transformNode = new SoTransform;
|
||||
transformNode->setMatrix(convert(transformMatrix));
|
||||
|
||||
sep->addChild(transformNode);
|
||||
sep->addChild(pcPreviewShape);
|
||||
|
||||
pcPreviewRoot->addChild(sep);
|
||||
}
|
||||
}
|
||||
} catch (const Base::Exception& e) {
|
||||
e.reportException();
|
||||
}
|
||||
Gui::coinRemoveAllChildren(pcRejectedRoot);
|
||||
|
||||
pcRoot->removeChild(pcRejectedRoot);
|
||||
|
||||
pcRejectedRoot->unref();
|
||||
ViewProvider::updatePreview();
|
||||
}
|
||||
|
||||
bool ViewProviderTransformed::onDelete(const std::vector<std::string> &s)
|
||||
Part::TopoShape ViewProviderTransformed::getPreviewShape() const
|
||||
{
|
||||
return ViewProvider::onDelete(s);
|
||||
if (auto feature = getObject<PartDesign::Transformed>()) {
|
||||
auto originals = feature->getOriginals();
|
||||
|
||||
if (originals.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (auto first = freecad_cast<PartDesign::Feature*>(originals.front())) {
|
||||
return first->PreviewShape.getShape();
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ViewProviderTransformed::handleTranformedResult(PartDesign::Transformed* pcTransformed) {
|
||||
void ViewProviderTransformed::handleTransformedResult(PartDesign::Transformed* pcTransformed) {
|
||||
unsigned rejected = 0;
|
||||
|
||||
TopoDS_Shape cShape = pcTransformed->rejected;
|
||||
TopExp_Explorer xp;
|
||||
xp.Init(cShape, TopAbs_SOLID);
|
||||
@@ -178,159 +172,28 @@ void ViewProviderTransformed::handleTranformedResult(PartDesign::Transformed* pc
|
||||
msg = msg.arg(rejected);
|
||||
}
|
||||
}
|
||||
auto error = pcTransformed->getDocument()->getErrorDescription(pcTransformed);
|
||||
if (error) {
|
||||
|
||||
if (const char* error = pcTransformed->getDocument()->getErrorDescription(pcTransformed)) {
|
||||
msg = msg.arg(QStringLiteral("<font color='red'>%1<br/></font>"));
|
||||
msg = msg.arg(QString::fromUtf8(error));
|
||||
} else {
|
||||
msg = msg.arg(QStringLiteral("<font color='green'>%1<br/></font>"));
|
||||
msg = msg.arg(QObject::tr("Transformation succeeded"));
|
||||
}
|
||||
|
||||
diagMessage = msg;
|
||||
signalDiagnosis(msg);
|
||||
|
||||
// Clear all the rejected stuff
|
||||
while (pcRejectedRoot->getNumChildren() > 7) {
|
||||
SoSeparator* sep = static_cast<SoSeparator*>(pcRejectedRoot->getChild(7));
|
||||
SoMultipleCopy* rejectedTrfms = static_cast<SoMultipleCopy*>(sep->getChild(2));
|
||||
Gui::coinRemoveAllChildren(rejectedTrfms);
|
||||
sep->removeChild(1);
|
||||
sep->removeChild(0);
|
||||
pcRejectedRoot ->removeChild(7);
|
||||
}
|
||||
|
||||
// Display the rejected transformations in red
|
||||
if (rejected > 0) {
|
||||
showRejectedShape(cShape);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewProviderTransformed::recomputeFeature(bool recompute)
|
||||
{
|
||||
PartDesign::Transformed* pcTransformed = getObject<PartDesign::Transformed>();
|
||||
if(recompute || (pcTransformed->isError() || pcTransformed->mustExecute()))
|
||||
auto* pcTransformed = getObject<PartDesign::Transformed>();
|
||||
|
||||
if (recompute || pcTransformed->isError() || pcTransformed->mustExecute()) {
|
||||
pcTransformed->recomputeFeature(true);
|
||||
|
||||
handleTranformedResult(pcTransformed);
|
||||
}
|
||||
|
||||
void ViewProviderTransformed::showRejectedShape(TopoDS_Shape shape)
|
||||
{
|
||||
try {
|
||||
// calculating the deflection value
|
||||
Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
|
||||
{
|
||||
Bnd_Box bounds;
|
||||
BRepBndLib::Add(shape, bounds);
|
||||
bounds.SetGap(0.0);
|
||||
bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
|
||||
}
|
||||
Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue();
|
||||
|
||||
// create or use the mesh on the data structure
|
||||
// Note: This DOES have an effect on shape
|
||||
Standard_Real AngDeflectionRads = Base::toRadians(AngularDeflection.getValue());
|
||||
BRepMesh_IncrementalMesh(shape, deflection, Standard_False, AngDeflectionRads, Standard_True);
|
||||
|
||||
// We must reset the location here because the transformation data
|
||||
// are set in the placement property
|
||||
TopLoc_Location aLoc;
|
||||
shape.Location(aLoc);
|
||||
|
||||
// count triangles and nodes in the mesh
|
||||
int nbrTriangles=0, nbrNodes=0;
|
||||
TopExp_Explorer Ex;
|
||||
for (Ex.Init(shape, TopAbs_FACE); Ex.More(); Ex.Next()) {
|
||||
Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc);
|
||||
// Note: we must also count empty faces
|
||||
if (!mesh.IsNull()) {
|
||||
nbrTriangles += mesh->NbTriangles();
|
||||
nbrNodes += mesh->NbNodes();
|
||||
}
|
||||
}
|
||||
|
||||
// create memory for the nodes and indexes
|
||||
SoCoordinate3* rejectedCoords = new SoCoordinate3();
|
||||
rejectedCoords ->point .setNum(nbrNodes);
|
||||
SoNormal* rejectedNorms = new SoNormal();
|
||||
rejectedNorms ->vector .setNum(nbrNodes);
|
||||
SoIndexedFaceSet* rejectedFaceSet = new SoIndexedFaceSet();
|
||||
rejectedFaceSet ->coordIndex .setNum(nbrTriangles*4);
|
||||
|
||||
// get the raw memory for fast fill up
|
||||
SbVec3f* verts = rejectedCoords ->point .startEditing();
|
||||
SbVec3f* norms = rejectedNorms ->vector .startEditing();
|
||||
int32_t* index = rejectedFaceSet ->coordIndex .startEditing();
|
||||
|
||||
// preset the normal vector with null vector
|
||||
for (int i=0; i < nbrNodes; i++)
|
||||
norms[i]= SbVec3f(0.0,0.0,0.0);
|
||||
|
||||
int FaceNodeOffset=0,FaceTriaOffset=0;
|
||||
for (Ex.Init(shape, TopAbs_FACE); Ex.More(); Ex.Next()) {
|
||||
const TopoDS_Face &actFace = TopoDS::Face(Ex.Current());
|
||||
|
||||
// get triangulation
|
||||
std::vector<gp_Pnt> points;
|
||||
std::vector<Poly_Triangle> facets;
|
||||
if (!Part::Tools::getTriangulation(actFace, points, facets))
|
||||
continue;
|
||||
|
||||
// get normal per vertex
|
||||
std::vector<gp_Vec> vertexnormals;
|
||||
Part::Tools::getPointNormals(points, facets, vertexnormals);
|
||||
|
||||
// getting size of node and triangle array of this face
|
||||
std::size_t nbNodesInFace = points.size();
|
||||
std::size_t nbTriInFace = facets.size();
|
||||
|
||||
for (std::size_t i = 0; i < points.size(); i++) {
|
||||
verts[FaceNodeOffset+i] = SbVec3f(points[i].X(), points[i].Y(), points[i].Z());
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < vertexnormals.size(); i++) {
|
||||
norms[FaceNodeOffset+i] = SbVec3f(vertexnormals[i].X(), vertexnormals[i].Y(), vertexnormals[i].Z());
|
||||
}
|
||||
|
||||
// cycling through the poly mesh
|
||||
for (std::size_t g=0; g < nbTriInFace; g++) {
|
||||
// Get the triangle
|
||||
Standard_Integer N1,N2,N3;
|
||||
facets[g].Get(N1,N2,N3);
|
||||
|
||||
// set the index vector with the 3 point indexes and the end delimiter
|
||||
index[FaceTriaOffset*4+4*g] = FaceNodeOffset+N1;
|
||||
index[FaceTriaOffset*4+4*g+1] = FaceNodeOffset+N2;
|
||||
index[FaceTriaOffset*4+4*g+2] = FaceNodeOffset+N3;
|
||||
index[FaceTriaOffset*4+4*g+3] = SO_END_FACE_INDEX;
|
||||
}
|
||||
|
||||
// counting up the per Face offsets
|
||||
FaceNodeOffset += nbNodesInFace;
|
||||
FaceTriaOffset += nbTriInFace;
|
||||
|
||||
// normalize all normals
|
||||
for (int i=0; i < nbrNodes; i++)
|
||||
norms[i].normalize();
|
||||
|
||||
// end the editing of the nodes
|
||||
rejectedCoords ->point .finishEditing();
|
||||
rejectedNorms ->vector .finishEditing();
|
||||
rejectedFaceSet ->coordIndex .finishEditing();
|
||||
|
||||
// fill in the transformation matrices
|
||||
SoMultipleCopy* rejectedTrfms = new SoMultipleCopy();
|
||||
rejectedTrfms->matrix.finishEditing();
|
||||
rejectedTrfms->addChild(rejectedFaceSet);
|
||||
SoSeparator* sep = new SoSeparator();
|
||||
sep->addChild(rejectedCoords);
|
||||
sep->addChild(rejectedNorms);
|
||||
sep->addChild(rejectedTrfms);
|
||||
pcRejectedRoot->addChild(sep);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
Base::Console().error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n",
|
||||
getObject()->getNameInDocument());
|
||||
}
|
||||
|
||||
updatePreview();
|
||||
|
||||
handleTransformedResult(pcTransformed);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#include "ViewProvider.h"
|
||||
|
||||
#include <Inventor/nodes/SoMultipleCopy.h>
|
||||
|
||||
namespace PartDesign {
|
||||
class Transformed;
|
||||
}
|
||||
@@ -45,9 +47,11 @@ public:
|
||||
// The feature name of the subclass
|
||||
virtual const std::string & featureName() const;
|
||||
std::string featureIcon() const;
|
||||
|
||||
void recomputeFeature(bool recompute=true);
|
||||
void setupContextMenu(QMenu*, QObject*, const char*) override;
|
||||
|
||||
bool onDelete(const std::vector<std::string> &) override;
|
||||
Part::TopoShape getPreviewShape() const override;
|
||||
|
||||
/// signals if the transformation contains errors
|
||||
boost::signals2::signal<void (QString msg)> signalDiagnosis;
|
||||
@@ -57,24 +61,19 @@ public:
|
||||
|
||||
Gui::ViewProvider *startEditing(int ModNum=0) override;
|
||||
|
||||
QString getMessage() const { return diagMessage; }
|
||||
|
||||
protected:
|
||||
bool setEdit(int ModNum) override;
|
||||
void unsetEdit(int ModNum) override;
|
||||
|
||||
void attachPreview() override;
|
||||
void updatePreview() override;
|
||||
|
||||
bool checkDlgOpen(TaskDlgTransformedParameters* transformedDlg);
|
||||
void handleTranformedResult(PartDesign::Transformed* transformed);
|
||||
|
||||
// node for the representation of rejected repetitions
|
||||
SoGroup * pcRejectedRoot{nullptr};
|
||||
void handleTransformedResult(PartDesign::Transformed* transformed);
|
||||
|
||||
Gui::CoinPtr<SoMultipleCopy> pcMultipleCopy;
|
||||
QString diagMessage;
|
||||
|
||||
public:
|
||||
void recomputeFeature(bool recompute=true);
|
||||
QString getMessage() const {return diagMessage;}
|
||||
|
||||
private:
|
||||
void showRejectedShape(TopoDS_Shape shape);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user