diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt
index 44aff6f11c..aabc377464 100755
--- a/src/Mod/Fem/CMakeLists.txt
+++ b/src/Mod/Fem/CMakeLists.txt
@@ -180,6 +180,7 @@ SET(FemObjects_SRCS
femobjects/constraint_bodyheatsource.py
femobjects/constraint_centrif.py
femobjects/constraint_currentdensity.py
+ femobjects/constraint_electricchargedensity.py
femobjects/constraint_electrostaticpotential.py
femobjects/constraint_flowvelocity.py
femobjects/constraint_initialflowvelocity.py
@@ -582,6 +583,7 @@ SET(FemGuiTaskPanels_SRCS
femtaskpanels/task_constraint_bodyheatsource.py
femtaskpanels/task_constraint_centrif.py
femtaskpanels/task_constraint_currentdensity.py
+ femtaskpanels/task_constraint_electricchargedensity.py
femtaskpanels/task_constraint_electrostaticpotential.py
femtaskpanels/task_constraint_flowvelocity.py
femtaskpanels/task_constraint_initialflowvelocity.py
@@ -627,6 +629,7 @@ SET(FemGuiViewProvider_SRCS
femviewprovider/view_constraint_bodyheatsource.py
femviewprovider/view_constraint_centrif.py
femviewprovider/view_constraint_currentdensity.py
+ femviewprovider/view_constraint_electricchargedensity.py
femviewprovider/view_constraint_electrostaticpotential.py
femviewprovider/view_constraint_flowvelocity.py
femviewprovider/view_constraint_initialflowvelocity.py
diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt
index 6fb0572ecd..cbe6e488db 100755
--- a/src/Mod/Fem/Gui/CMakeLists.txt
+++ b/src/Mod/Fem/Gui/CMakeLists.txt
@@ -369,6 +369,7 @@ SET(FemGuiIcon_SVG
SET(FemGuiSymbol_IV
Resources/symbols/ConstraintContact.iv
Resources/symbols/ConstraintDisplacement.iv
+ Resources/symbols/ConstraintElectricChargeDensity.iv
Resources/symbols/ConstraintElectrostaticPotential.iv
Resources/symbols/ConstraintCurrentDensity.iv
Resources/symbols/ConstraintFixed.iv
@@ -405,6 +406,7 @@ SET(FemGuiPythonUI_SRCS
Resources/ui/ConstraintSectionPrint.ui
Resources/ui/CurrentDensity.ui
Resources/ui/DlgSettingsNetgen.ui
+ Resources/ui/ElectricChargeDensity.ui
Resources/ui/ElectrostaticPotential.ui
Resources/ui/ElementFluid1D.ui
Resources/ui/ElementGeometry1D.ui
diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp
index e71185cacd..20c52dbcbf 100644
--- a/src/Mod/Fem/Gui/Command.cpp
+++ b/src/Mod/Fem/Gui/Command.cpp
@@ -1416,6 +1416,9 @@ void CmdFemCompEmConstraints::activated(int iMsg)
else if (iMsg == 2) {
rcCmdMgr.runCommandByName("FEM_ConstraintMagnetization");
}
+ else if (iMsg == 3) {
+ rcCmdMgr.runCommandByName("FEM_ConstraintElectricChargeDensity");
+ }
else {
return;
}
@@ -1441,6 +1444,8 @@ Gui::Action* CmdFemCompEmConstraints::createAction()
cmd1->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_ConstraintCurrentDensity"));
QAction* cmd2 = pcAction->addAction(QString());
cmd2->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_ConstraintMagnetization"));
+ QAction* cmd3 = pcAction->addAction(QString());
+ cmd3->setIcon(Gui::BitmapFactory().iconFromTheme("FEM_ConstraintElectricChargeDensity"));
_pcAction = pcAction;
languageChange();
@@ -1502,6 +1507,20 @@ void CmdFemCompEmConstraints::languageChange()
cmd2->setStatusTip(QApplication::translate("FEM_ConstraintMagnetization",
ConstraintMagnetization->getStatusTip()));
}
+
+ Gui::Command* ConstraintElectricChargeDensity =
+ rcCmdMgr.getCommandByName("FEM_ConstraintElectricChargeDensity");
+ if (ConstraintElectricChargeDensity) {
+ QAction* cmd3 = a[3];
+ cmd3->setText(QApplication::translate("FEM_ConstraintElectricChargeDensity",
+ ConstraintElectricChargeDensity->getMenuText()));
+ cmd3->setToolTip(
+ QApplication::translate("FEM_ConstraintElectricChargeDensity",
+ ConstraintElectricChargeDensity->getToolTipText()));
+ cmd3->setStatusTip(
+ QApplication::translate("FEM_ConstraintElectricChargeDensity",
+ ConstraintElectricChargeDensity->getStatusTip()));
+ }
}
bool CmdFemCompEmConstraints::isActive()
diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc
index dd132e54fc..4033dfc273 100755
--- a/src/Mod/Fem/Gui/Resources/Fem.qrc
+++ b/src/Mod/Fem/Gui/Resources/Fem.qrc
@@ -15,6 +15,7 @@
icons/FEM_ConstraintContact.svg
icons/FEM_ConstraintCurrentDensity.svg
icons/FEM_ConstraintDisplacement.svg
+ icons/FEM_ConstraintElectricChargeDensity.svg
icons/FEM_ConstraintElectrostaticPotential.svg
icons/FEM_ConstraintFixed.svg
icons/FEM_ConstraintFlowVelocity.svg
@@ -127,6 +128,7 @@
ui/ConstraintTie.ui
ui/CurrentDensity.ui
ui/DlgSettingsNetgen.ui
+ ui/ElectricChargeDensity.ui
ui/ElectrostaticPotential.ui
ui/ElementFluid1D.ui
ui/ElementGeometry1D.ui
diff --git a/src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintElectricChargeDensity.svg b/src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintElectricChargeDensity.svg
new file mode 100644
index 0000000000..4e8402350a
--- /dev/null
+++ b/src/Mod/Fem/Gui/Resources/icons/FEM_ConstraintElectricChargeDensity.svg
@@ -0,0 +1,430 @@
+
+
diff --git a/src/Mod/Fem/Gui/Resources/symbols/ConstraintElectricChargeDensity.iv b/src/Mod/Fem/Gui/Resources/symbols/ConstraintElectricChargeDensity.iv
new file mode 100644
index 0000000000..1689168a72
--- /dev/null
+++ b/src/Mod/Fem/Gui/Resources/symbols/ConstraintElectricChargeDensity.iv
@@ -0,0 +1,74 @@
+#Inventor V2.1 ascii
+
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+#/***************************************************************************
+# * Copyright (c) 2025 Mario Passaglia *
+# * *
+# * This file is part of FreeCAD. *
+# * *
+# * FreeCAD is free software: you can redistribute it and/or modify it *
+# * under the terms of the GNU Lesser General Public License as *
+# * published by the Free Software Foundation, either version 2.1 of the *
+# * License, or (at your option) any later version. *
+# * *
+# * FreeCAD is distributed in the hope that it will be useful, but *
+# * WITHOUT ANY WARRANTY; without even the implied warranty of *
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+# * Lesser General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU Lesser General Public *
+# * License along with FreeCAD. If not, see *
+# * . *
+# * *
+# **************************************************************************
+
+
+Separator {
+
+ Separator {
+
+ Translation {
+ translation 0 0.5 0
+
+ }
+ Sphere {
+ radius 0.5
+
+ }
+ Translation {
+ translation 0 2.0 0
+
+ }
+ BaseColor {
+ rgb 0.17 0.46 1.0
+
+ }
+ Sphere {
+ radius 0.5
+
+ }
+ Translation {
+ translation 0 -1.375 0
+
+ }
+ BaseColor {
+ rgb 1 1 1
+
+ }
+ Cylinder {
+ radius 0.1
+ height 0.75
+
+ }
+ Translation {
+ translation 0 .625 0
+
+ }
+ Cone {
+ bottomRadius 0.25
+ height 0.5
+
+ }
+ }
+}
diff --git a/src/Mod/Fem/Gui/Resources/ui/ElectricChargeDensity.ui b/src/Mod/Fem/Gui/Resources/ui/ElectricChargeDensity.ui
new file mode 100644
index 0000000000..77def88519
--- /dev/null
+++ b/src/Mod/Fem/Gui/Resources/ui/ElectricChargeDensity.ui
@@ -0,0 +1,187 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 350
+ 40
+
+
+
+ Analysis feature properties
+
+
+ -
+
+
+
-
+
+
-
+
+
+ Mode:
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 0
+
+
+
+
-
+
+
+ Free surface charge density
+
+
-
+
+
+ Density:
+
+
+
+ -
+
+
+ true
+
+
+ C/mm^2
+
+
+ Qt::AlignLeft|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ true
+
+
+ 1.000000000000000
+
+
+ 0.000000000000000
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ -
+
+
+ Free volume charge density
+
+
-
+
+
+ Density:
+
+
+
+ -
+
+
+ true
+
+
+ C/mm^3
+
+
+ Qt::AlignLeft|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ true
+
+
+ 1.000000000000000
+
+
+ 0.000000000000000
+
+
+
+
+
+
+
+
+ 2
+
+
+
+ -
+
+
+ Free total charge
+
+
-
+
+
+ Total Charge:
+
+
+
+ -
+
+
+ true
+
+
+ C
+
+
+ Qt::AlignLeft|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ true
+
+
+ 1.000000000000000
+
+
+ 0.000000000000000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gui::QuantitySpinBox
+ QWidget
+
+
+
+
+
+
diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp
index 345632754e..7740d29c19 100644
--- a/src/Mod/Fem/Gui/Workbench.cpp
+++ b/src/Mod/Fem/Gui/Workbench.cpp
@@ -246,7 +246,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const
elec->setCommand("&Electromagnetic boundary conditions");
*elec << "FEM_ConstraintElectrostaticPotential"
<< "FEM_ConstraintCurrentDensity"
- << "FEM_ConstraintMagnetization";
+ << "FEM_ConstraintMagnetization"
+ << "FEM_ConstraintElectricChargeDensity";
Gui::MenuItem* fluid = new Gui::MenuItem;
fluid->setCommand("&Fluid boundary conditions");
diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py
index b8893e5d20..17a8b436f9 100644
--- a/src/Mod/Fem/ObjectsFem.py
+++ b/src/Mod/Fem/ObjectsFem.py
@@ -132,6 +132,20 @@ def makeConstraintDisplacement(doc, name="ConstraintDisplacement"):
return obj
+def makeConstraintElectricChargeDensity(doc, name="ElectricChargeDensity"):
+ """makeConstraintElectricChargeDensity(document, [name]):
+ makes a Fem ElectricChargeDensity object"""
+ obj = doc.addObject("Fem::ConstraintPython", name)
+ from femobjects import constraint_electricchargedensity
+
+ constraint_electricchargedensity.ConstraintElectricChargeDensity(obj)
+ if FreeCAD.GuiUp:
+ from femviewprovider import view_constraint_electricchargedensity
+
+ view_constraint_electricchargedensity.VPConstraintElectricChargeDensity(obj.ViewObject)
+ return obj
+
+
def makeConstraintElectrostaticPotential(doc, name="ConstraintElectrostaticPotential"):
"""makeConstraintElectrostaticPotential(document, [name]):
makes a Fem ElectrostaticPotential object"""
diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py
index 69bed9352f..89dad73b83 100644
--- a/src/Mod/Fem/femcommands/commands.py
+++ b/src/Mod/Fem/femcommands/commands.py
@@ -221,6 +221,22 @@ class _ConstraintCurrentDensity(CommandManager):
self.do_activated = "add_obj_on_gui_set_edit"
+class _ConstraintElectricChargeDensity(CommandManager):
+ "The FEM_ConstraintElectricChargeDensity command definition"
+
+ def __init__(self):
+ super().__init__()
+ self.pixmap = "FEM_ConstraintElectricChargeDensity"
+ self.menutext = Qt.QT_TRANSLATE_NOOP(
+ "FEM_ConstraintElectricChargeDensity", "Electric charge density"
+ )
+ self.tooltip = Qt.QT_TRANSLATE_NOOP(
+ "FEM_ConstraintElectricChargeDensity", "Creates a electric charge density"
+ )
+ self.is_active = "with_analysis"
+ self.do_activated = "add_obj_on_gui_set_edit"
+
+
class _ConstraintElectrostaticPotential(CommandManager):
"The FEM_ConstraintElectrostaticPotential command definition"
@@ -1171,6 +1187,7 @@ FreeCADGui.addCommand("FEM_ConstantVacuumPermittivity", _ConstantVacuumPermittiv
FreeCADGui.addCommand("FEM_ConstraintBodyHeatSource", _ConstraintBodyHeatSource())
FreeCADGui.addCommand("FEM_ConstraintCentrif", _ConstraintCentrif())
FreeCADGui.addCommand("FEM_ConstraintCurrentDensity", _ConstraintCurrentDensity())
+FreeCADGui.addCommand("FEM_ConstraintElectricChargeDensity", _ConstraintElectricChargeDensity())
FreeCADGui.addCommand("FEM_ConstraintElectrostaticPotential", _ConstraintElectrostaticPotential())
FreeCADGui.addCommand("FEM_ConstraintFlowVelocity", _ConstraintFlowVelocity())
FreeCADGui.addCommand("FEM_ConstraintInitialFlowVelocity", _ConstraintInitialFlowVelocity())
diff --git a/src/Mod/Fem/femobjects/constraint_electricchargedensity.py b/src/Mod/Fem/femobjects/constraint_electricchargedensity.py
new file mode 100644
index 0000000000..fb2b9a6b16
--- /dev/null
+++ b/src/Mod/Fem/femobjects/constraint_electricchargedensity.py
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# ***************************************************************************
+# * Copyright (c) 2025 Mario Passaglia *
+# * *
+# * This file is part of FreeCAD. *
+# * *
+# * FreeCAD is free software: you can redistribute it and/or modify it *
+# * under the terms of the GNU Lesser General Public License as *
+# * published by the Free Software Foundation, either version 2.1 of the *
+# * License, or (at your option) any later version. *
+# * *
+# * FreeCAD is distributed in the hope that it will be useful, but *
+# * WITHOUT ANY WARRANTY; without even the implied warranty of *
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+# * Lesser General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU Lesser General Public *
+# * License along with FreeCAD. If not, see *
+# * . *
+# * *
+# ***************************************************************************
+
+__title__ = "FreeCAD FEM constraint electric charge density document object"
+__author__ = "Mario Passaglia"
+__url__ = "https://www.freecad.org"
+
+## @package constraint_electricchargedensity
+# \ingroup FEM
+# \brief constraint electric charge density object
+
+from . import base_fempythonobject
+
+_PropHelper = base_fempythonobject._PropHelper
+
+
+class ConstraintElectricChargeDensity(base_fempythonobject.BaseFemPythonObject):
+
+ Type = "Fem::ConstraintElectricChargeDensity"
+
+ def __init__(self, obj):
+ super().__init__(obj)
+
+ for prop in self._get_properties():
+ prop.add_to_object(obj)
+
+ def _get_properties(self):
+ prop = []
+
+ prop.append(
+ _PropHelper(
+ type="App::PropertyVolumeChargeDensity",
+ name="SourceChargeDensity",
+ group="Electric Charge Density",
+ doc="Free electric charge per unit volume at the sources",
+ value="0 C/mm^3",
+ )
+ )
+ prop.append(
+ _PropHelper(
+ type="App::PropertySurfaceChargeDensity",
+ name="InterfaceChargeDensity",
+ group="Electric Charge Density",
+ doc="Free electric charge per unit surface at the boundaries",
+ value="0 C/mm^2",
+ )
+ )
+ prop.append(
+ _PropHelper(
+ type="App::PropertyElectricCharge",
+ name="TotalCharge",
+ group="Electric Charge Density",
+ doc="Total free electric charge",
+ value="0 C",
+ )
+ )
+ prop.append(
+ _PropHelper(
+ type="App::PropertyEnumeration",
+ name="Mode",
+ group="Electric Charge Density",
+ doc="Switch quantity input mode",
+ value=["Interface", "Source", "Total Interface", "Total Source"],
+ )
+ )
+
+ return prop
diff --git a/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py b/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py
index 6ffba76461..bc49f4ee05 100644
--- a/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py
+++ b/src/Mod/Fem/femsolver/elmer/equations/electrostatic_writer.py
@@ -30,6 +30,8 @@ __url__ = "https://www.freecad.org"
## \addtogroup FEM
# @{
+from FreeCAD import Units
+
from .. import sifio
@@ -133,8 +135,8 @@ class ESwriter:
elif obj.BoundaryCondition == "Neumann":
self.write.boundary(
name,
- "Surface Charge Density",
- obj.SurfaceChargeDensity.getValueAs("C/m^2").Value,
+ "Electric Flux",
+ obj.ElectricFluxDensity.getValueAs("C/m^2").Value,
)
if obj.PotentialConstant:
self.write.boundary(name, "Potential Constant", True)
@@ -146,5 +148,60 @@ class ESwriter:
self.write.boundary(name, "Capacitance Body", obj.CapacitanceBody)
self.write.handled(obj)
+ for obj in self.write.getMember("Fem::ConstraintElectricChargeDensity"):
+ if obj.Mode not in ["Interface", "Total Interface"]:
+ continue
+
+ size = 0
+ items = []
+ for feat, sub_elem in obj.References:
+ for name in sub_elem:
+ sub = feat.getSubObject(name)
+ if sub.ShapeType == "Face":
+ size += sub.Area
+ items.append(name)
+ elif sub.ShapeType == "Edge":
+ size += sub.Length
+ items.append(name)
+
+ if items:
+ if obj.Mode == "Interface":
+ density = obj.InterfaceChargeDensity.getValueAs("C/m^2").Value
+ elif obj.Mode == "Total Interface":
+ area = Units.Quantity(f"{size} mm^2")
+ density = (obj.TotalCharge / area).getValueAs("C/m^2").Value
+ for name in items:
+ self.write.boundary(name, "! FreeCAD Name", obj.Label)
+ self.write.boundary(name, "Surface Charge Density", round(density, 6))
+ self.write.handled(obj)
+
+ def handleElectrostaticBodyForces(self):
+ for obj in self.write.getMember("Fem::ConstraintElectricChargeDensity"):
+ if obj.Mode not in ["Source", "Total Source"]:
+ continue
+
+ size = 0
+ items = []
+ for feat, sub_elem in obj.References:
+ for name in sub_elem:
+ sub = feat.getSubObject(name)
+ if sub.ShapeType == "Solid":
+ size += sub.Volume
+ items.append(name)
+ elif sub.ShapeType == "Face":
+ size += sub.Area
+ items.append(name)
+
+ if items:
+ if obj.Mode == "Source":
+ density = obj.SourceChargeDensity.getValueAs("C/m^3").Value
+ elif obj.Mode == "Total Source":
+ vol = Units.Quantity(f"{size} mm^3")
+ density = (obj.TotalCharge / vol).getValueAs("C/m^3").Value
+ for name in items:
+ self.write.bodyForce(name, "! FreeCAD Name", obj.Label)
+ self.write.bodyForce(name, "Charge Density", round(density, 6))
+ self.write.handled(obj)
+
## @}
diff --git a/src/Mod/Fem/femsolver/elmer/writer.py b/src/Mod/Fem/femsolver/elmer/writer.py
index 834d87bcc1..b55833c754 100644
--- a/src/Mod/Fem/femsolver/elmer/writer.py
+++ b/src/Mod/Fem/femsolver/elmer/writer.py
@@ -471,6 +471,7 @@ class Writer:
if activeIn:
ESW.handleElectrostaticConstants()
ESW.handleElectrostaticBndConditions()
+ ESW.handleElectrostaticBodyForces()
ESW.handleElectrostaticMaterial(activeIn)
# -------------------------------------------------------------------------------------------
diff --git a/src/Mod/Fem/femtaskpanels/task_constraint_electricchargedensity.py b/src/Mod/Fem/femtaskpanels/task_constraint_electricchargedensity.py
new file mode 100644
index 0000000000..1d082454ae
--- /dev/null
+++ b/src/Mod/Fem/femtaskpanels/task_constraint_electricchargedensity.py
@@ -0,0 +1,171 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# ***************************************************************************
+# * Copyright (c) 2025 Mario Passaglia *
+# * *
+# * This file is part of FreeCAD. *
+# * *
+# * FreeCAD is free software: you can redistribute it and/or modify it *
+# * under the terms of the GNU Lesser General Public License as *
+# * published by the Free Software Foundation, either version 2.1 of the *
+# * License, or (at your option) any later version. *
+# * *
+# * FreeCAD is distributed in the hope that it will be useful, but *
+# * WITHOUT ANY WARRANTY; without even the implied warranty of *
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+# * Lesser General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU Lesser General Public *
+# * License along with FreeCAD. If not, see *
+# * . *
+# * *
+# ***************************************************************************
+
+__title__ = "FreeCAD FEM constraint electric charge density task panel"
+__author__ = "Mario Passaglia"
+__url__ = "https://www.freecad.org"
+
+## @package task_constraint_electricchargedensity
+# \ingroup FEM
+# \brief task panel for constraint electric charge density object
+
+from PySide import QtCore
+
+import FreeCAD
+import FreeCADGui
+
+from femguiutils import selection_widgets
+
+from femtools import membertools
+from . import base_femtaskpanel
+
+
+class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
+
+ def __init__(self, obj):
+ super().__init__(obj)
+
+ self.parameter_widget = FreeCADGui.PySideUic.loadUi(
+ FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/ElectricChargeDensity.ui"
+ )
+
+ self.init_parameter_widget()
+
+ QtCore.QObject.connect(
+ self.parameter_widget.qsb_source_charge_density,
+ QtCore.SIGNAL("valueChanged(Base::Quantity)"),
+ self.source_charge_density_changed,
+ )
+ QtCore.QObject.connect(
+ self.parameter_widget.qsb_interface_charge_density,
+ QtCore.SIGNAL("valueChanged(Base::Quantity)"),
+ self.interface_charge_density_changed,
+ )
+ QtCore.QObject.connect(
+ self.parameter_widget.qsb_total_charge,
+ QtCore.SIGNAL("valueChanged(Base::Quantity)"),
+ self.total_charge_changed,
+ )
+ QtCore.QObject.connect(
+ self.parameter_widget.cb_mode,
+ QtCore.SIGNAL("currentIndexChanged(int)"),
+ self.mode_changed,
+ )
+
+ # geometry selection widget
+ # start with Solid in list!
+ self.selection_widget = selection_widgets.GeometryElementsSelection(
+ obj.References, ["Solid", "Face", "Edge"], False, False
+ )
+
+ # form made from param and selection widget
+ self.form = [self.parameter_widget, self.selection_widget]
+
+ analysis = obj.getParentGroup()
+ self._mesh = None
+ self._part = None
+ if analysis is not None:
+ self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject")
+ if self._mesh is not None:
+ self._part = self._mesh.Shape
+ self._partVisible = None
+ self._meshVisible = None
+
+ def open(self):
+ if self._mesh is not None and self._part is not None:
+ self._meshVisible = self._mesh.ViewObject.isVisible()
+ self._partVisible = self._part.ViewObject.isVisible()
+ self._mesh.ViewObject.hide()
+ self._part.ViewObject.show()
+
+ def reject(self):
+ self.restore_visibility()
+ self.selection_widget.finish_selection()
+ return super().reject()
+
+ def accept(self):
+ self.obj.References = self.selection_widget.references
+ self.obj.SourceChargeDensity = self.source_charge_density
+ self.obj.InterfaceChargeDensity = self.interface_charge_density
+ self.obj.TotalCharge = self.total_charge
+ self.obj.Mode = self.mode
+
+ self.selection_widget.finish_selection()
+ self.restore_visibility()
+ return super().accept()
+
+ def restore_visibility(self):
+ if self._mesh is not None and self._part is not None:
+ if self._meshVisible:
+ self._mesh.ViewObject.show()
+ else:
+ self._mesh.ViewObject.hide()
+ if self._partVisible:
+ self._part.ViewObject.show()
+ else:
+ self._part.ViewObject.hide()
+
+ def init_parameter_widget(self):
+ self.source_charge_density = self.obj.SourceChargeDensity
+ self.interface_charge_density = self.obj.InterfaceChargeDensity
+ self.total_charge = self.obj.TotalCharge
+ FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_source_charge_density).bind(
+ self.obj, "SourceChargeDensity"
+ )
+ self.parameter_widget.qsb_source_charge_density.setProperty(
+ "value", self.source_charge_density
+ )
+
+ FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_interface_charge_density).bind(
+ self.obj, "InterfaceChargeDensity"
+ )
+ self.parameter_widget.qsb_interface_charge_density.setProperty(
+ "value", self.interface_charge_density
+ )
+
+ FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_total_charge).bind(
+ self.obj, "TotalCharge"
+ )
+ self.parameter_widget.qsb_total_charge.setProperty("value", self.total_charge)
+
+ self.mode = self.obj.Mode
+ self.mode_enum = self.obj.getEnumerationsOfProperty("Mode")
+ self.parameter_widget.cb_mode.addItems(self.mode_enum)
+ index = self.mode_enum.index(self.mode)
+ self.parameter_widget.cb_mode.setCurrentIndex(index)
+ self.mode_changed(index)
+
+ def source_charge_density_changed(self, base_quantity_value):
+ self.source_charge_density = base_quantity_value
+
+ def interface_charge_density_changed(self, base_quantity_value):
+ self.interface_charge_density = base_quantity_value
+
+ def total_charge_changed(self, base_quantity_value):
+ self.total_charge = base_quantity_value
+
+ def mode_changed(self, index):
+ self.mode = self.mode_enum[index]
+ if self.mode in ["Total Interface", "Total Source"]:
+ index = 2
+ self.parameter_widget.sw_mode.setCurrentIndex(index)
diff --git a/src/Mod/Fem/femviewprovider/view_constraint_electricchargedensity.py b/src/Mod/Fem/femviewprovider/view_constraint_electricchargedensity.py
new file mode 100644
index 0000000000..59517f2c4e
--- /dev/null
+++ b/src/Mod/Fem/femviewprovider/view_constraint_electricchargedensity.py
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# ***************************************************************************
+# * Copyright (c) 2025 Mario Passaglia *
+# * *
+# * This file is part of FreeCAD. *
+# * *
+# * FreeCAD is free software: you can redistribute it and/or modify it *
+# * under the terms of the GNU Lesser General Public License as *
+# * published by the Free Software Foundation, either version 2.1 of the *
+# * License, or (at your option) any later version. *
+# * *
+# * FreeCAD is distributed in the hope that it will be useful, but *
+# * WITHOUT ANY WARRANTY; without even the implied warranty of *
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+# * Lesser General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU Lesser General Public *
+# * License along with FreeCAD. If not, see *
+# * . *
+# * *
+# ***************************************************************************
+
+__title__ = "FreeCAD FEM constraint electric charge view provider"
+__author__ = "Mario Passaglia"
+__url__ = "https://www.freecad.org"
+
+## @package view_constraint_electricchargedensity
+# \ingroup FEM
+# \brief view provider for the constraint electric charge density object
+
+from femtaskpanels import task_constraint_electricchargedensity
+from . import view_base_femconstraint
+
+
+class VPConstraintElectricChargeDensity(view_base_femconstraint.VPBaseFemConstraint):
+
+ def __init__(self, vobj):
+ super().__init__(vobj)
+ mat = vobj.ShapeAppearance[0]
+ mat.DiffuseColor = (1.0, 0.0, 0.2, 0.0)
+ vobj.ShapeAppearance = mat
+
+ def setEdit(self, vobj, mode=0):
+ return view_base_femconstraint.VPBaseFemConstraint.setEdit(
+ self, vobj, mode, task_constraint_electricchargedensity._TaskPanel
+ )
+
+ def attach(self, vobj):
+ super().attach(vobj)
+ vobj.loadSymbol(self.resource_symbol_dir + "ConstraintElectricChargeDensity.iv")