Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gui: Add Part variant logic #19735

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft

Conversation

pieterhijma
Copy link
Contributor

@pieterhijma pieterhijma commented Feb 20, 2025

This PR is an outcome of FPA grant proposal Research Variant Parts.

This PR mainly adds GUI support and improves the Part::Variant introduced in #19733.

This builds on (and currently also includes) #19733.

This PR is not meant to be merged as is but it contains a prototype with a potential option to have Variant Parts in FreeCAD. I discuss the implementation in detail in this forum post and beyond.

How it can be used is explained in this forum post.

This commit does not do anything but just adds logic to intercept
getters and setters to properties.  This is used to compute shapes from
document objects.

In particular for document objects, it creates a stack of document
objects that is used to write and read properties to and from when
executing a document object that is the target of a variant.
This commit makes use of the logic from the previous commit to intercept
access to properties by context document objects.  This is used to
compute shapes from document objects.

Since there is no logic to actually set a context, all calls to
acquire a context will fail, so effectively all is a no-op currently.
This adds Part::Variant based on an App::VariantExtension that makes use
of DocumentObject contexts to compute shapes from document objects.
In the Property View, exposed properties are colored purple and there is
a menu action to expose or unexpose properties.
- add a command and button for variants
- adopt support icon for a variant with an overlay
- hide context document objects and add them to the group
@github-actions github-actions bot added Mod: Core Issue or PR touches core sections (App, Gui, Base) of FreeCAD Mod: Part Related to the Part Workbench Mod: Sketcher Related to the Sketcher Workbench labels Feb 20, 2025
for (const auto& id : exp->getIdentifiers()) {
Property* prop = id.first.getProperty();
if (prop) {
DocumentObject* obj = dynamic_cast<DocumentObject*>(prop->getContainer());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dynamic_cast is slow. I don't believe we can use that here for a function that might be called very often. Consider using isDerivedFrom

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Base::freecad_dynamic_cast would be fine there? It essentially is doing the isDerivedFrom call and static cast so it should be pretty cheap.

std::vector<Property*> propsObj;
obj->getPropertyList(propsObj);
for (auto prop : propsObj) {
auto link = dynamic_cast<PropertyLinkBase*>(prop);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dynamic_cast :(

Comment on lines +861 to +864
bool DocumentObject::isExposed(const Property* prop) const
{
return prop->testStatus(Property::Exposed);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would one call DocumentObject::isExposed(prop) and not just prop->testStatus(Exposed) directly?

bool include = true;
if (excludeExposed) {
auto propNames = dep.second;
include = !std::all_of(propNames.begin(), propNames.end(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this cause performance issues? Hmmm

throw NoContextException();
}

auto derivedProp = dynamic_cast<const DerivedType*>(prop);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dynamic_cast :(

static_assert(std::is_member_function_pointer_v<FuncType>,
"Func must be a member function pointer.");

auto* derivedProp = dynamic_cast<DerivedType*>(getContextProperty(CreatePropOption::Create));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dynamic_cast :(

{
Property* prop = this->getContextProperty(option);
if (prop) {
return dynamic_cast<PropertyListsT<T, ListT, ParentT>*>(prop);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dynamic_cast :(

set_difference(currentAdoptedExposedProps,
adoptedExposedProps,
std::inserter(propsToRemove, propsToRemove.end()));
for_each(propsToRemove, [this](const App::Property* prop) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use normal for(const auto& x : xs)?

@@ -176,6 +177,56 @@ bool StdCmdVarSet::isActive()
return hasActiveDocument();
}


//===========================================================================
// Std_VarSet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Std_VarSet
// Std_Variant

@@ -24,6 +24,7 @@
#include "PreCompiled.h"

#ifndef _PreComp_
#include <boost/algorithm/cxx11/all_of.hpp>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused?

@marcuspollio
Copy link
Contributor

@pieterhijma Great !
Adding the video you made on the PR description could help for user testing =D
Thanks for your work !

@pieterhijma
Copy link
Contributor Author

@pieterhijma Great ! Adding the video you made on the PR description could help for user testing =D Thanks for your work !

Yes, sorry, cyclic dependencies (the forum refers to this and this should refer to the forum).... The description now points to the forum in which I describe the implementation. I've also added a link to the video there (for quick reference).

@pieterhijma
Copy link
Contributor Author

@benj5378, Thanks for the review. As this is a prototype and a draft, I haven't looked very much into your comments but I think you have a point in all your cases. I think for now, it is much more helpful to look at the bigger picture, such as the design and the implication of adding this to FreeCAD. See the forum topic that I link to in the discussion. Would you be able to comment on that as well? Would be appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Mod: Core Issue or PR touches core sections (App, Gui, Base) of FreeCAD Mod: Part Related to the Part Workbench Mod: Sketcher Related to the Sketcher Workbench
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants