Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/CI_master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@

name: FreeCAD master CI

on: [workflow_dispatch, push, pull_request, merge_group]
on:
push:
branches: [ "SimplerBody" ]
pull_request:
branches: [ "SimplerBody" ]
merge_group:
branches: [ "SimplerBody" ]
workflow_dispatch:


concurrency:
group: FC-CI-${{ github.head_ref || github.run_id }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ name: "CodeQL Advanced"

on:
push:
branches: [ "main" ]
branches: [ "SimplerBody" ]
pull_request:
branches: [ "main" ]
branches: [ "SimplerBody" ]
schedule:
- cron: '28 12 * * 6'

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scorecards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
schedule:
- cron: '20 7 * * 2'
push:
branches: ["main"]
branches: ["SimplerBody"]

# Declare default permissions as read only.
permissions: read-all
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/sub_weeklyBuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ jobs:
include:
- { target: linux-64, os: ubuntu-22.04 }
- { target: linux-arm64, os: ubuntu-22.04-arm }
- { target: osx-64, os: macos-13 }
- { target: osx-arm64, os: macos-latest }
- { target: win-64, os: windows-latest }
# - { target: osx-64, os: macos-13 }
# - { target: osx-arm64, os: macos-latest }
fail-fast: false

runs-on: ${{ matrix.os }}
Expand Down
388 changes: 388 additions & 0 deletions aqtinstall.log

Large diffs are not rendered by default.

52 changes: 12 additions & 40 deletions src/App/DocumentObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "Application.h"
#include "ElementNamingUtils.h"
#include "Document.h"
#include "Part.h"
#include "DocumentObject.h"
#include "DocumentObjectPy.h"
#include "DocumentObjectExtension.h"
Expand Down Expand Up @@ -102,51 +103,22 @@ void DocumentObject::printInvalidLinks() const
// Truncate the invalid object list name strings for readability, if they happen to be very
// long.
std::vector<App::DocumentObject*> invalid_linkobjs;
std::string objnames, scopenames;
GeoFeatureGroupExtension::getInvalidLinkObjects(this, invalid_linkobjs);
for (auto& obj : invalid_linkobjs) {
objnames += obj->getNameInDocument();
objnames += " ";
for (auto& scope : obj->getParents()) {
if (scopenames.length() > 80) {
scopenames += "... ";
break;
}

scopenames += scope.first->getNameInDocument();
scopenames += " ";
}

if (objnames.length() > 80) {
objnames += "... ";
break;
}
}

if (objnames.empty()) {
objnames = "N/A";
}
else {
objnames.pop_back();
}

if (scopenames.empty()) {
scopenames = "N/A";
}
else {
scopenames.pop_back();
}

Base::Console().warning("%s: Link(s) to object(s) '%s' go out of the allowed scope '%s'. "
std::string objname, scopename;
objname= obj->getNameInDocument();
if (objname.empty()) objname = "N/A";
const App::Part* scope = App::Part::getPartOfObject(obj);
scopename = scope ? scope->getNameInDocument() : "N/A";
if (scopename.empty()) scopename = "N/A";
Base::Console().warning("%s: Link(s) to object(s) '%s' go out of the allowed scope '%s'. "
"Instead, the linked object(s) reside within '%s'.\n",
getTypeId().getName(),
objnames.c_str(),
objname.c_str(),
getNameInDocument(),
scopenames.c_str());
}
catch (const Base::Exception& e) {
e.reportException();
}
scopename.c_str());
}
} catch (const Base::Exception& e) {e.reportException();}
}

App::DocumentObjectExecReturn* DocumentObject::recompute()
Expand Down
62 changes: 57 additions & 5 deletions src/App/GeoFeatureGroupExtension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include "Datums.h"
#include "OriginGroupExtension.h"

#include <cstring> // for std::strcmp


using namespace App;

Expand Down Expand Up @@ -108,6 +110,45 @@ DocumentObject* GeoFeatureGroupExtension::getGroupOfObject(const DocumentObject*
return nullptr;
}


const App::DocumentObject* GeoFeatureGroupExtension::getBoundaryGroupOfObject(const App::DocumentObject* obj)
{
if (!obj) return nullptr;

// nearest GeoFeatureGroup (upstream meaning)
const App::DocumentObject* g =
obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())
? obj
: App::GeoFeatureGroupExtension::getGroupOfObject(obj);

// Skip groups that opted out as a boundary (actsAsGroupBoundary == false)
while (g) {
auto* ext = g->getExtensionByType<App::GeoFeatureGroupExtension>();
if (!ext) break; // not a geofeature group (shouldn’t happen) → stop
if (ext->actsAsGroupBoundary()) // this one is a boundary → stop here
break;
// transparent group → climb to its parent group
g = App::GeoFeatureGroupExtension::getGroupOfObject(g);
}

return g; // may be nullptr (top level), or the nearest boundary group
}


Base::Placement GeoFeatureGroupExtension::globalGroupPlacementInBoundary(const App::DocumentObject* obj)
{
Base::Placement result;
const App::DocumentObject* boundary = getBoundaryGroupOfObject(obj);
const App::DocumentObject* container = getGroupOfObject(obj);
while (container && container != boundary) {
if (auto* prop = dynamic_cast<const App::PropertyPlacement*>(container->getPropertyByName("Placement"))) {
result = prop->getValue() * result;
}
container = getGroupOfObject(container);
}
return result;
}

Base::Placement GeoFeatureGroupExtension::globalGroupPlacement()
{
if (getExtendedObject()->isRecomputing()) {
Expand Down Expand Up @@ -245,6 +286,19 @@ void GeoFeatureGroupExtension::extensionOnChanged(const Property* p)
}
}

if (p == &this->placement() && !this->actsAsGroupBoundary()
&& !getExtendedObject()->isRestoring()
&& !getExtendedObject()->getDocument()->isPerformingTransaction()) {

for (auto* obj : this->Group.getValues()) {
if (!obj) continue;

if (auto* prop = obj->getPropertyByName("Placement"))
prop->touch();
}
}


App::GroupExtension::extensionOnChanged(p);
}

Expand Down Expand Up @@ -514,13 +568,11 @@ void GeoFeatureGroupExtension::getInvalidLinkObjects(const DocumentObject* obj,
return;
}

// no cross CS link for local links.
// 1) Local links must not cross the nearest movable group boundary
auto result = getScopedObjectsFromLinks(obj, LinkScope::Local);
auto group = obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())
? obj
: getGroupOfObject(obj);
auto group = GeoFeatureGroupExtension::getBoundaryGroupOfObject(obj);
for (auto link : result) {
if (getGroupOfObject(link) != group) {
if (GeoFeatureGroupExtension::getBoundaryGroupOfObject(link) != group) {
vec.push_back(link);
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/App/GeoFeatureGroupExtension.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ class AppExport GeoFeatureGroupExtension: public App::GroupExtension
* system
*/
Base::Placement globalGroupPlacement();
static Base::Placement globalGroupPlacementInBoundary(const App::DocumentObject* obj);

// New: capability flag — does this group act as a link/scope boundary?
// Default: true (current upstream behavior).
bool actsAsGroupBoundary() const noexcept { return m_actsAsGroupBoundary; }
void setActsAsGroupBoundary(bool v) noexcept { m_actsAsGroupBoundary = v; }

// New: helper used by selection/validation to hop over transparent groups.
// Returns the nearest GeoFeatureGroup that *acts as a boundary*; nullptr = top level.
static const App::DocumentObject* getBoundaryGroupOfObject(const App::DocumentObject* obj);

/// Returns true if the given DocumentObject is DocumentObjectGroup but not GeoFeatureGroup
static bool isNonGeoGroup(const DocumentObject* obj)
Expand Down Expand Up @@ -150,6 +160,7 @@ class AppExport GeoFeatureGroupExtension: public App::GroupExtension

static void recursiveCSRelevantLinks(const App::DocumentObject* obj,
std::vector<App::DocumentObject*>& vec);
bool m_actsAsGroupBoundary = true;
};

using GeoFeatureGroupExtensionPython =
Expand Down
18 changes: 18 additions & 0 deletions src/App/Part.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ Part::Part()
ADD_PROPERTY(Color, (1.0, 1.0, 1.0, 0.0)); // set transparent -> not used

GroupExtension::initExtension(this);

if (auto* gext = this->getExtensionByType<App::GeoFeatureGroupExtension>()) {
gext->setActsAsGroupBoundary(false); // Parts are transparent boundaries
}

}

Part::~Part() = default;
Expand Down Expand Up @@ -108,6 +113,19 @@ PyObject* Part::getPyObject()
return Py::new_reference_to(PythonObject);
}


void App::Part::onDocumentRestored()
{
App::GeoFeature::onDocumentRestored();

if (auto* gext = this->getExtensionByType<App::GeoFeatureGroupExtension>()) {
// imposta a false solo se è "true" (evita di sovrascrivere scelte esplicite salvate)
if (gext->actsAsGroupBoundary())
gext->setActsAsGroupBoundary(false);
}
}


void Part::handleChangedPropertyType(Base::XMLReader& reader,
const char* TypeName,
App::Property* prop)
Expand Down
2 changes: 2 additions & 0 deletions src/App/Part.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class AppExport Part: public App::GeoFeature, public App::OriginGroupExtension
static App::Part* getPartOfObject(const DocumentObject* obj, bool recursive = true);

PyObject* getPyObject() override;
void onDocumentRestored() override;

};

// using PartPython = App::FeaturePythonT<Part>;
Expand Down
6 changes: 5 additions & 1 deletion src/Gui/CommandDoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1603,7 +1603,11 @@ void StdCmdPlacement::activated(int iMsg)
bool StdCmdPlacement::isActive()
{
std::vector<App::DocumentObject*> sel = Gui::Selection().getObjectsOfType(App::GeoFeature::getClassTypeId());
return (sel.size() == 1 && ! sel.front()->isFreezed());
if(sel.size() != 1 || sel.front()->isFreezed()) return false;
App::Property* prop = sel.front()->getPropertyByName("Placement");
if(!prop) return false;
if (prop->testStatus(App::Property::Hidden)) return false;
return true;
}

//===========================================================================
Expand Down
Loading