DXF: Place objects in layer all at once rather than one at a time to improve DXF import speed dramatically. (#16596)

* Place objects in layer all at once rather than one at a time.
This reduces (by a factor of the number of objects in the layer) the number of times that the layer contents are traversed to set the properties of the contained objects.
This means the layer insertion of O(n) rather then O(n^2) on the number of objects.
Also remove a loop invariant in view_layer so the chidren are not traversed if colours or appearnces are not inherited from the layer.
Fixes #15732

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Kevin Martin
2024-09-23 05:39:02 -04:00
committed by GitHub
parent 980303b618
commit c9887d9400
3 changed files with 34 additions and 36 deletions

View File

@@ -228,16 +228,15 @@ class ViewProviderLayer:
# Return if the property does not exist
if not hasattr(vobj, prop):
return
# If the override properties are not set return without change
if prop == "LineColor" and not vobj.OverrideLineColorChildren:
return
elif prop == "ShapeAppearance" and not vobj.OverrideShapeAppearanceChildren:
return
for target_obj in obj.Group:
target_vobj = target_obj.ViewObject
# If the override properties are not set return without change
if prop == "LineColor" and not vobj.OverrideLineColorChildren:
return
elif prop == "ShapeAppearance" and not vobj.OverrideShapeAppearanceChildren:
return
# This checks that the property exists in the target object,
# and then sets the target property accordingly
if hasattr(target_vobj, prop):

View File

@@ -112,14 +112,8 @@ bool ImpExpDxfRead::ReadEntitiesSection()
}
}
if (m_preserveLayers) {
// Hide the Hidden layers if possible (if GUI exists)
// We do this now rather than when the layer is created so all objects
// within the layers also become hidden.
for (auto& layerEntry : Layers) {
auto layer = (Layer*)layerEntry.second;
if (layer->DraftLayerView != nullptr && layer->Hidden) {
PyObject_CallMethod(layer->DraftLayerView, "hide", nullptr);
}
((Layer*)layerEntry.second)->FinishLayer();
}
}
return true;
@@ -610,16 +604,38 @@ ImpExpDxfRead::Layer::Layer(const std::string& name,
std::string&& lineType,
PyObject* drawingLayer)
: CDxfRead::Layer(name, color, std::move(lineType))
, DraftLayer(drawingLayer)
, GroupContents(
drawingLayer == nullptr
? nullptr
: (App::PropertyLinkListHidden*)(((App::FeaturePythonPyT<App::DocumentObjectPy>*)
drawingLayer)
->getPropertyContainerPtr())
->getDynamicPropertyByName("Group"))
, DraftLayerView(drawingLayer == nullptr ? nullptr
: PyObject_GetAttrString(drawingLayer, "ViewObject"))
{}
ImpExpDxfRead::Layer::~Layer()
{
Py_XDECREF(DraftLayer);
Py_XDECREF(DraftLayerView);
}
void ImpExpDxfRead::Layer::FinishLayer() const
{
if (GroupContents != nullptr) {
// We have to move the object to layer->DraftLayer
// The DraftLayer will have a Proxy attribute which has a addObject attribute which we
// call with (draftLayer, draftObject) Checking from python, the layer is a
// App::FeaturePython, and its Proxy is a draftobjects.layer.Layer
GroupContents->setValue(Contents);
}
if (DraftLayerView != nullptr && Hidden) {
// Hide the Hidden layers if possible (if GUI exists)
// We do this now rather than when the layer is created so all objects
// within the layers also become hidden.
PyObject_CallMethod(DraftLayerView, "hide", nullptr);
}
}
CDxfRead::Layer*
ImpExpDxfRead::MakeLayer(const std::string& name, ColorIndex_t color, std::string&& lineType)
{
@@ -669,26 +685,7 @@ ImpExpDxfRead::MakeLayer(const std::string& name, ColorIndex_t color, std::strin
void ImpExpDxfRead::MoveToLayer(App::DocumentObject* object) const
{
if (m_preserveLayers) {
static PyObject* addObjectName =
PyUnicode_FromString("addObject"); // This never gets freed, we always have a reference
auto layer = static_cast<const Layer*>(m_entityAttributes.m_Layer);
if (layer->DraftLayer != nullptr) {
// We have to move the object to layer->DraftLayer
// The DraftLayer will have a Proxy attribute which has a addObject attribute which we
// call with (draftLayer, draftObject) Checking from python, the layer is a
// App::FeaturePython, and its Proxy is a draftobjects.layer.Layer
PyObject* proxy = PyObject_GetAttrString(layer->DraftLayer, "Proxy");
if (proxy != nullptr) {
// TODO: De we have to check if the method exists? The legacy importer does.
PyObject_CallMethodObjArgs(proxy,
addObjectName,
layer->DraftLayer,
object->getPyObject(),
nullptr);
Py_DECREF(proxy);
return;
}
}
static_cast<Layer*>(m_entityAttributes.m_Layer)->Contents.push_back(object);
}
// TODO: else Hide the object if it is in a Hidden layer? That won't work because we've cleared
// out m_entityAttributes.m_Layer

View File

@@ -143,8 +143,10 @@ protected:
void operator=(const Layer&) = delete;
void operator=(Layer&&) = delete;
~Layer() override;
PyObject* const DraftLayer;
PyObject* const DraftLayerView;
std::vector<App::DocumentObject*> Contents;
void FinishLayer() const;
App::PropertyLinkListHidden* GroupContents;
};
using FeaturePythonBuilder =