FreeCAD Logo FreeCAD 1.0
  • English Afrikaans Arabic Belarusian Catalan Czech German Greek Spanish Spanish Basque Finnish Filipino French Galician Croatian Hungarian Indonesian Italian Japanese Kabyle Korean Lithuanian Dutch Norwegian Bokmal Polish Portuguese Portuguese Romanian Russian Slovak Slovenian Serbian Swedish Turkish Ukrainian Valencian Vietnamese Chinese Chinese
  • Features
  • Download
  • Blog
  • Documentation
    Documentation index Getting started Users documentation The FreeCAD manual Workbenches documentation Python coding documentation C++ coding documentation Tutorials Frequently asked questions Privacy policy About FreeCAD
  • Contribute
    How to help Sponsor Report a bug Make a pull request Jobs and funding Contribution guidelines Developers handbook Translations
  • Community
    Code of conduct Forum The FPA GitHub GitLab Codeberg Mastodon Matrix IRC IRC via Webchat Gitter Discord Reddit Twitter Facebook LinkedIn Calendar
  • ♥ Donate

Donate

$
SEPA Information
Please set up your SEPA bank transfer to:
Beneficiary: The FreeCAD project association
IBAN: BE04 0019 2896 4531
BIC/SWIFT: GEBABEBBXXX
Bank agency: BNP Paribas Fortis
Address: Rue de la Station 64, 1360 Perwez, Belgium

While Stripe doesn't support monthly donations, you can still become a sponsor! Simply make a one-time donation equivalent to 12 months of support, and you'll gain access to the corresponding sponsoring tier. It's an easy and flexible way to contribute.

If you are not sure or not able to commit to a regular donation, but still want to help the project, you can do a one-time donation, of any amount.

Choose freely the amount you wish to donate one time only.

You can support FreeCAD by sponsoring it as an individual or organization through various platforms. Sponsorship provides a steady income for developers, allowing the FPA to plan ahead and enabling greater investment in FreeCAD. To encourage sponsorship, we offer different tiers, and unless you choose to remain anonymous, your name or company logo will be featured on our website accordingly.

from 1 USD / 1 EUR per month. You will not have your name displayed here, but you will have helped the project a lot anyway. Together, normal sponsors maintain the project on its feet as much as the bigger sponsors.

from 25 USD / 25 EUR per month. Your name or company name is displayed on this page.

from 100 USD / 100 EUR per month. Your name or company name is displayed on this page, with a link to your website, and a one-line description text.

from 200 USD / 200 EUR per month. Your name or company name and logo displayed on this page, with a link to your website and a custom description text. Companies that have helped FreeCAD early on also appear under Gold sponsors.

Instead of donating each month, you might find it more comfortable to make a one-time donation that, when divided by twelve, would give you right to enter a sponsoring tier. Don't hesitate to do so!

Choose freely the amount you wish to donate each month.

Please inform your forum name or twitter handle as a notein your transfer, or reach to us, so we can give you proper credits!

Macro cross section

{{Macro |Name=Cross_section |Icon=Macro_cross_section.png |Description=Macro to display a cross-section of the objects in the scene: the cross-section plane can be moved by a slider bar. |Author=aleph0 |Version=0.10 |Date=2020-12-19 |FCVersion=0.15 and above |Download=[https://www.freecadweb.org/wiki/https://raw.githubusercontent.com/FreeCAD/FreeCAD-documentation/master/wiki/images/f/f5/Macro_cross_section.png ToolBar Icon] }}

Description

Macro to display a cross-section of the objects in the scene: the cross-section plane can be moved by a slider bar.

Use

  • To run the macro, first download it from this site and install it in your macros directory,
  • then use the menu to call up your list of macros and double-click on this one.
  • It will display a default cross-section and pop up a window to enable you to set the cross-sectioning parameters.
  • Closing the pop-up window will restore the scene to its previous state before the macro was started.

LINKS

See forum

Look down right: \"Keep the sectional view\"

Script

Changes by Mario52 include.

Changes by Sam include.

Changes by Gift include.

Changes by duke24 include.

Changes by g.becu include.

Changes by Chris_G include.

ToolBar Icon

Macro cross section.FCMacro

{{MacroCode|code=

-- coding: utf-8 --

"""


  •                                                                     *
  • This widget makes an interactively moveable cross-section of the *
  • currently visible objects in the currently active document. The *
  • cross-sectioning plane is specified by its normal, and the cross- *
  • section can be moved along that normal using a slider bar. It can *
  • show the cross-section either as an outline or a view of the sliced *
  • objects. To run the macro, first download it from this site and *
  • install it in your macros directory, then use the menu to call up *
  • your list of macros and double-click on this one. It will display *
  • a default cross-section and pop up a window to enable you to set *
  • the cross-sectioning parameters. Closing the pop-up window will *
  • restore the scene to its previous state before the macro was *
  • started. *

  • Copyright (c) 2016 Richard P. Parkins, M. A. *
  • This file is a supplement to the FreeCAD CAx development system. *
  • This program is free software; you can redistribute it and/or modify *
  • it under the terms of the GNU Lesser General Public License (LGPL) *
  • as published by the Free Software Foundation; either version 2 of *
  • the License, or (at your option) any later version. *
  • for detail see the LICENCE text file. *
  • This software 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 Library General Public License for more details. *
  • You should have received a copy of the GNU Library General Public *
  • License along with this macro; if not, write to the Free Software *
  • Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
  • USA *

    """ title = "Cross-Section" author = "Aleph0" version = "00.10" date = "19/12/2020"

"29/01/2016" "10/06/2016" "29/09/2016 * 2" "17/08/2017" "06/09/2017" "17/09/2017" "04/07/2019" "31/08/2019" "19/12/2020"

Upgrade:

17/08/2017 by Sam #https://forum.freecadweb.org/viewtopic.php?f=28&t=15084&start=10#p187030

06/09/2017 17/09/2017 by Gift #https://www.forum.freecadweb.org/viewtopic.php?f=13&t=24130

04/07/2019 by duke24 replace tab to space #https://forum.freecadweb.org/viewtopic.php?f=13&t=37449

31/08/2019 by g.becu adding line 334 #https://forum.freecadweb.org/viewtopic.php?f=28&t=15084&start=20#p330351

19/12/2020 by Chris_G : exlude App.Part from the list of input objects + many code style fixes (PEP8)

See forum : https://forum.freecadweb.org/viewtopic.php?f=22&t=53423

Comment = "Dynamic cross section viewer" Wiki = "http://www.freecadweb.org/wiki/index.php?title=Macro_cross_section" Help = "see first few lines of macro text" Status = "stable" Requires = "freecad 0.15"

OS: Ubuntu 14.04.3 LTS # OS: Windows 10

Word size of OS: 64-bit # Word size of OS: 64-bit

Word size of FreeCAD: 64-bit # Word size of FreeCAD: 64-bit

Version: 0.15.4671 (Git) # Version: 0.19.17171 (Git)

Branch: releases/FreeCAD-0-15 # Build type: Release

Hash: 244b3aef360841646cbfe80a1b225c8b39c8380c# Branch: master

Python version: 2.7.6 # Hash: d19470a9711ea604f3ca6c93e46afadf64d5bb87

Qt version: 4.8.6 # Python version: 3.6.6

Coin version: 4.0.0a # Qt version: 5.6.2

OCC version: 6.8.0.oce-0.17 # Coin version: 4.0.0a

# OCC version: 7.3.0

import PySide from PySide import QtCore, QtGui import FreeCAD as App import FreeCADGui import Part import Draft from FreeCAD import Base

try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: def _fromUtf8(s): return s

try: _encoding = QtGui.QApplication.UnicodeUTF8

def _translate(context, text, disambig):
    return QtGui.QApplication.translate(context, text, disambig, _encoding)

except AttributeError: def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig)

width = 350 # width of our window height = 310 # height of our window global FreeCADRootWindow # main window before we start

This is the interactive window that the macro creates

Its main function is to have a close box and tidy up when closed

class CrossSectionWindow(PySide.QtGui.QMainWindow):

automagically called when the window is created

def __init__(self):
    super(CrossSectionWindow, self).__init__()
    self.setWindowFlags(PySide.QtCore.Qt.WindowStaysOnTopHint)
    self.setWindowTitle(_translate(
        "MainWindow", "Cross-section", None))

    # Create and set the window's widget, which does all the work
    self.child = CrossSection(self)
    self.setCentralWidget(self.child)
    self.child.initUI(self)
    if self.child.startup_failed:
        self.destroy()
    else:
        # Position our window relative to the FreeCAD root
        self.setPosition(FreeCADRootWindow)
        self.child.show()
        self.show()

# User closed the window, tidy up
def closeEvent(self, event):
    self.child.restoreObjects()

# Set a sensible default position for the window
# With FreeCAD's default layout, this will be over the docking area
# so it will not obscure the 3D view
def setPosition(self, parent):
    geom = parent.geometry()
    xpos = geom.left() + 50
    ypos = geom.center().y() - height / 2
    self.setGeometry(xpos, ypos, width, height)
    self.setFixedSize(width, height)

This is the widget which does almost all of the work

Widgets don't have close boxes, so closing is dealt with in CrossSectionWindow

class CrossSection(PySide.QtGui.QWidget):

Lay out the interactive elements

def initUI(self, parent):
    self.parent = parent
    font = QtGui.QFont()
    font.setFamily("Times New Roman")
    font.setPointSize(10)
    font.setWeight(10)
    font.setBold(True)
    self.hideObjects()

    margin = 10
    alw = 20  # axis label width
    sbp = margin + alw + margin  # spin boxes to right of axis labels
    slw = width - 2 * margin  # width of slider and progress bar
    ypos = margin

    self.setObjectName(_fromUtf8("CrossSection"))

    # The cross-section plane is defined by its normal
    # The length of the normal is immaterial as long as it is nonzero
    self.label_1 = QtGui.QLabel(self)
    self.label_1.setGeometry(QtCore.QRect(margin, ypos, slw, 22))
    self.label_1.setObjectName(_fromUtf8("label_1"))
    self.label_1.setText(_translate(
        "MainWindow", "Sliding axis direction", None))
    self.label_1.setToolTip(_translate(
        "MainWindow",
        "Cross-section is taken perpendicular to this axis", None))
    ypos = ypos + 30

    self.label_2 = QtGui.QLabel(self)
    self.label_2.setGeometry(QtCore.QRect(margin, ypos, alw, 25))
    self.label_2.setObjectName(_fromUtf8("label_2"))
    self.label_2.setText(_translate("MainWindow", "X", None))

    self.doubleSpinBox_X = QtGui.QDoubleSpinBox(self)
    self.doubleSpinBox_X.setGeometry(QtCore.QRect(sbp, ypos, 62, 25))
    self.doubleSpinBox_X.setMinimum(-10000.0)
    self.doubleSpinBox_X.setMaximum(10000.0)
    self.doubleSpinBox_X.setValue(0.0)
    self.doubleSpinBox_X.setSingleStep(1)
    self.doubleSpinBox_X.setObjectName(_fromUtf8("doubleSpinBox_X"))
    self.doubleSpinBox_X.valueChanged.connect(
        self.on_doubleSpinBox_X_valueChanged)
    self.doubleSpinBox_X.setToolTip(_translate(
        "MainWindow", "Sliding axis X", None))
    ypos = ypos + 30

    self.label_3 = QtGui.QLabel(self)
    self.label_3.setGeometry(QtCore.QRect(margin, ypos, alw, 25))
    self.label_3.setObjectName(_fromUtf8("label_3"))
    self.label_3.setText(_translate("MainWindow", "Y", None))

    self.doubleSpinBox_Y = QtGui.QDoubleSpinBox(self)
    self.doubleSpinBox_Y.setGeometry(QtCore.QRect(sbp, ypos, 62, 25))
    self.doubleSpinBox_Y.setMinimum(-10000.0)
    self.doubleSpinBox_Y.setMaximum(10000.0)
    self.doubleSpinBox_Y.setValue(0.0)
    self.doubleSpinBox_Y.setSingleStep(1)
    self.doubleSpinBox_Y.setObjectName(_fromUtf8("doubleSpinBox_Y"))
    self.doubleSpinBox_Y.valueChanged.connect(
        self.on_doubleSpinBox_Y_valueChanged)
    self.doubleSpinBox_Y.setToolTip(_translate(
        "MainWindow", "Sliding axis Y", None))
    ypos = ypos + 30

    self.label_4 = QtGui.QLabel(self)
    self.label_4.setGeometry(QtCore.QRect(margin, ypos, alw, 25))
    self.label_4.setObjectName(_fromUtf8("label_4"))
    self.label_4.setText(_translate("MainWindow", "Z", None))

    self.doubleSpinBox_Z = QtGui.QDoubleSpinBox(self)
    self.doubleSpinBox_Z.setGeometry(QtCore.QRect(sbp, ypos, 62, 25))
    self.doubleSpinBox_Z.setMinimum(-10000.0)
    self.doubleSpinBox_Z.setMaximum(10000.0)
    self.doubleSpinBox_Z.setValue(1.0)
    self.doubleSpinBox_Z.setSingleStep(1)
    self.doubleSpinBox_Z.setObjectName(_fromUtf8("doubleSpinBox_Z"))
    self.doubleSpinBox_Z.valueChanged.connect(
        self.on_doubleSpinBox_Z_valueChanged)
    self.doubleSpinBox_Z.setToolTip(
        _translate("MainWindow", "Sliding axis Z", None))
    ypos = ypos + 40
    # Make the interactive slider control
    # As you move this slider with the mouse, the cross-section slides
    # through the model
    self.label_5 = QtGui.QLabel(self)
    self.label_5.setGeometry(QtCore.QRect(margin, ypos, slw, 22))
    self.label_5.setObjectName(_fromUtf8("label_5"))
    self.label_5.setText(_translate(
        "MainWindow", "Position along axis", None))
    ypos = ypos + 30

    self.horizontalSlider = QtGui.QSlider(self)
    self.horizontalSlider.setGeometry(QtCore.QRect(margin, ypos, slw - 50, 20))
    self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)
    self.horizontalSlider.setInvertedAppearance(False)
    self.horizontalSlider.setObjectName(_fromUtf8("horizontalSlider"))
    self.horizontalSlider.setRange(0, 100)
    self.horizontalSlider.setValue(int(self.fraction * 100.0))
    self.horizontalSlider.setToolTip(_translate(
        "MainWindow", "Slide to move cross-section along axis", None))

    # must be called after setValue()
    self.horizontalSlider.valueChanged.connect(self.on_horizontal_slider)
    ypos = ypos + 30

    self.progressBar_1 = QtGui.QProgressBar(self)
    self.progressBar_1.setGeometry(QtCore.QRect(margin, ypos, slw - 50, 23))
    self.progressBar_1.setValue(int(self.fraction * 100.0))
    self.progressBar_1.setOrientation(QtCore.Qt.Horizontal)
    self.progressBar_1.setAlignment(QtCore.Qt.AlignCenter)
    self.progressBar_1.setObjectName(_fromUtf8("progressBar_1"))
    self.progressBar_1.setToolTip(_translate(
        "MainWindow", "Percent position of cross-section", None))
    ypos = ypos + 40

################################## add self.SpinBox_PBar = QtGui.QSpinBox(self) self.SpinBox_PBar.setGeometry(QtCore.QRect(sbp+255, ypos - 40, 45, 23)) self.SpinBox_PBar.setMinimum(0.0) self.SpinBox_PBar.setMaximum(100.0) self.SpinBox_PBar.setValue(int(self.fraction * 100.0)) self.SpinBox_PBar.setSingleStep(1) self.SpinBox_PBar.setObjectName(_fromUtf8("SpinBox_PBar")) self.SpinBox_PBar.valueChanged.connect(self.on_SpinBox_PBar_valueChanged) self.SpinBox_PBar.setToolTip(_translate( "MainWindow", "Sliding percent", None)) ################################# add

    # Select the display format for the cross-section
    # This button shows a wire line in the cross-section plane
    self.radioButton_1 = QtGui.QRadioButton(self)
    self.radioButton_1.setGeometry(QtCore.QRect(margin, ypos, slw, 20))
    self.radioButton_1.setText(_fromUtf8("Outline"))
    self.radioButton_1.setChecked(True)
    self.radioButton_1.toggled.connect(self.onRadioButton)
    self.radioButton_1.setObjectName(_fromUtf8("radioButton_1"))
    self.radioButton_1.setToolTip(_translate(
        "MainWindow", "Make cross-section as wire outline", None))
    ypos = ypos + 30

    # Select the display format for the cross-section
    # This button shows a normal 3D display with everything above the
    # cross-section plane cut away
    self.radioButton_2 = QtGui.QRadioButton(self)
    self.radioButton_2.setGeometry(QtCore.QRect(margin, ypos, slw, 20))
    self.radioButton_2.setText(_fromUtf8("Cut objects"))
    self.radioButton_2.setChecked(False)
    self.radioButton_2.toggled.connect(self.onRadioButton)
    self.radioButton_2.setObjectName(_fromUtf8("radioButton_2"))
    self.radioButton_2.setToolTip(_translate(
        "MainWindow", "Make cross-section as cut objects", None))

##################################

Keep the sectional view

    self.CB_00 = QtGui.QCheckBox(self)
    self.CB_00.setText(_fromUtf8("Keep the sectional view"))
    self.CB_00.setGeometry(QtCore.QRect(margin+168, ypos-30, slw, 20))
    self.CB_00.setObjectName(_fromUtf8("CB_00"))
    self.CB_00.setChecked(False)
    self.CB_00.setToolTip(_translate(
        "MainWindow", "Keep the sectional view or erase", None))

##################################

# Called at macro start up by initUI()
def hideObjects(self):
    # Initialise the cross-section state variables
    self.startup_failed = False
    self.fraction = 0.5
    self.axisX = 0.0
    self.axisY = 0.0
    self.axisZ = 1.0
    self.cross_section_type = 1

    # We must have something to do a cross-section on
    if App.ActiveDocument is None:
        QtGui.QMessageBox.warning(None, _translate("MainWindow",
            "Cross-section", None),
            _translate("MainWindow", "There is no Active Document\n" +
                "Create one and run this macro again.", None),
            QtGui.QMessageBox.Cancel,
            QtGui.QMessageBox.Cancel)
        self.startup_failed = True
        self.parent.destroy()  # This will close the window
    else:

        # Make a list of the user's objects
        # WARNING!!
        # This list is persistent. We'll get confused if the user deletes or
        # adds objects while the macro is active
        self.oblist = []  # App.ActiveDocument.Objects
        for obj in App.ActiveDocument.Objects:
            try:
                obj.getPropertyByName("Shape")
                self.oblist.append(obj)
            except AttributeError:
                pass
        # self.oblist = [obj for obj in self.oblist if hasattr(obj,"Shape")]
        # Create the cross-section object
        self.cs = App.ActiveDocument.addObject("Part::Feature", "Generated__cross-section")
        self.OriginalVisibilities = list()
        self.xmin = 1000.0
        self.xmax = -1000.0
        self.ymin = 1000.0
        self.ymax = -1000.0
        self.zmin = 1000.0
        self.zmax = -1000.0

n = 0

for p in self.oblist: # stupid Python list has no length function

n = n + 1

############################# Skip the ######################## b0 = [] for x0 in self.oblist: if str(x0) != "": b0.append(x0) self.oblist = b0 n = len(self.oblist) ###############################################################################

Make a list of the visible objects and make them invisible while

        # the macro is active
        # Also we compute the bounding box of the model
        for i in range(n):
            vis = self.oblist[i].ViewObject.Visibility
            self.OriginalVisibilities.append(vis)
            if vis:
                if self.oblist[i].TypeId != str("Drawing::FeatureViewPython"):   # add
                    self.oblist[i].ViewObject.Visibility = False
                    b = self.oblist[i].Shape.BoundBox
                    if b.XMin < self.xmin:
                        self.xmin = b.XMin
                    if b.XMax > self.xmax:
                        self.xmax = b.XMax
                    if b.YMin < self.ymin:
                        self.ymin = b.YMin
                    if b.YMax > self.ymax:
                        self.ymax = b.YMax
                    if b.ZMin < self.zmin:
                        self.zmin = b.ZMin
                    if b.ZMax > self.zmax:
                        self.zmax = b.ZMax
        # Moan and give up if there is nothing to cross-section
        if self.xmax <= self.xmin \
            or self.ymax <= self.ymin \
                or self.zmax <= self.zmin:
            QtGui.QMessageBox.warning(None, _translate("MainWindow",
                "Cross-section", None),
                _translate("MainWindow",
                "There are no visible solid objects\n" +
                "Create some and run this macro again.", None),
                QtGui.QMessageBox.Cancel,
                QtGui.QMessageBox.Cancel)
            self.restoreObjects()
            self.startup_failed = True
            App.ActiveDocument.removeObject("Generated__cross_section")
            self.parent.destroy()  # This will close the window
        else:
            # Trigger initial display
            self.updateAxis()

# Called when macro is closed
# Restore the original visibility of the user's objects
# and destroy our cross-section object
def restoreObjects(self):

    n = 0
    for p in self.oblist:  # stupid Python list has no length function
        n = n + 1
    for i in range(n):
        self.oblist[i].ViewObject.Visibility = self.OriginalVisibilities[i]
    try:
        if self.CB_00.isChecked() is False:
            App.ActiveDocument.removeObject("Generated__cross_section")
    except Exception:
        None

# Something has changed, recalculate the cross-section
def updateGui(self):
    # default to no visible cross-ection
    self.cs.ViewObject.Visibility = False

    # check if the sliding axis is invalid
    if self.xdir == 0.0 and self.ydir == 0.0 and self.zdir == 0.0 :
        QtGui.QMessageBox.warning(None, _translate("MainWindow",
            "Cross-section", None),
            _translate("MainWindow", "The sliding axis has zero length\n" +
                "Please set a valid axis.", None),
            QtGui.QMessageBox.Ok,
            QtGui.QMessageBox.Ok)
    else:

        # First we compute the 0% and 100% positions on the sliding axis
        if self.xdir < 0.0:
            x = self.xmax + self.fraction * self.xdir
        else:
            x = self.xmin + self.fraction * self.xdir
        if self.ydir < 0.0:
            y = self.ymax + self.fraction * self.ydir
        else:
            y = self.ymin + self.fraction * self.ydir
        if self.zdir < 0.0:
            z = self.zmax + self.fraction * self.zdir
        else:
            z = self.zmin + self.fraction * self.zdir

        r = 2 * max(self.xmax - self.xmin, self.ymax - self.ymin,
                    self.zmax - self.xmin)

        # Display the dimensions
        dimDep = "X " + str(x) + " mm , Y " + str(y) + " mm , Z " + str(z) + " mm"
        App.Console.PrintMessage(dimDep + "\n")

        # Create a big enough disc in the cross-section plane
        c = Part.makeCircle(r, Base.Vector(x, y, z),
                            Base.Vector(self.xdir, self.ydir, self.zdir))
        f = Part.Face(Part.Wire(c))
        part_list = list()  # list for cross-section parts
        n = 0
        for p in self.oblist:  # stupid Python list has no length function
            n = n + 1
        something = 0
        if self.cross_section_type == 1:
            # wire line cross-section
            for i in range(n):
                if self.oblist[i].TypeId != str("Drawing::FeatureViewPython"):  # add
                    if self.OriginalVisibilities[i]:
                        ob = self.oblist[i].Shape.section(f)
                        # check for valid section part
                        if ob.BoundBox.XMin <= ob.BoundBox.XMax:
                            part_list.append(ob)
                            something = 1
        else:
            # cut shape cross-section
            # extrude our cross-ection disc into a cylinder
            cyl = f.extrude(Base.Vector(self.xdir, self.ydir, self.zdir))
            doc = App.ActiveDocument
            for i in range(n):
                if self.oblist[i].TypeId != str("Drawing::FeatureViewPython"):  # add
                    if self.OriginalVisibilities[i]:
                        if (self.oblist[i].Shape.Volume <= 0.0):
                            continue
                        acut = doc.addObject("Part::Cut", "Cut")
                        abase = Draft.clone(self.oblist[i])
                        abase.ViewObject.DiffuseColor = self.oblist[i].ViewObject.DiffuseColor
                        abase.ViewObject.Transparency = self.oblist[i].ViewObject.Transparency
                        doc.recompute()
                        atool = doc.addObject("Part::Feature")
                        atool.Shape = cyl
                        atool.ViewObject.ShapeColor = self.oblist[i].ViewObject.ShapeColor  # (0.25,0.57,0.35)
                        atool.ViewObject.Transparency = self.oblist[i].ViewObject.Transparency
                        doc.recompute()
                        acut.Base = abase
                        acut.Tool = atool
                        acut.ViewObject.DiffuseColor = abase.ViewObject.DiffuseColor
                        doc.recompute()
                        if acut.Shape.isValid() and acut.Shape.Volume > 0.0:
                            ob = doc.addObject("Part::Feature")
                            ob.Shape = acut.Shape
                            ob.ViewObject.DiffuseColor = acut.ViewObject.DiffuseColor
                            doc.recompute()
                            part_list.append(ob)
                            something = 2
                        doc.removeObject(acut.Name)
                        doc.recompute()
                        doc.removeObject(abase.Name)
                        doc.recompute()
                        doc.removeObject(atool.Name)
                        doc.recompute()

        if something == 1:
            s = Part.makeCompound(part_list)
            if s.isValid():
                self.cs.Shape = s
                self.cs.ViewObject.Visibility = True
        if something == 2:
            feature = App.ActiveDocument.addObject("Part::Compound", "Compound")
            feature.Links = part_list
            App.ActiveDocument.recompute()
            if feature.Shape.isValid():
                self.cs.Shape = feature.Shape.copy()
                self.cs.ViewObject.DiffuseColor = feature.ViewObject.DiffuseColor
                self.cs.ViewObject.Visibility = True
                App.ActiveDocument.recompute()
            for od in part_list:
                App.ActiveDocument.removeObject(od.Name)
                App.ActiveDocument.recompute()
            App.ActiveDocument.removeObject(feature.Name)
        FreeCADGui.updateGui()

# User changed axis vector
# Compute a new axis vector whose length just covers the model
def updateAxis(self):
    ldir = 0.0
    if self.axisX != 0.0:
        ldir = (self.xmax - self.xmin) / abs(self.axisX)
    if self.axisY != 0.0:
        ldir = max(ldir, (self.ymax - self.ymin) / abs(self.axisY))
    if self.axisZ != 0.0:
        ldir = max(ldir, (self.zmax - self.zmin) / abs(self.axisZ))
    self.xdir = self.axisX * ldir
    self.ydir = self.axisY * ldir
    self.zdir = self.axisZ * ldir
    self.updateGui()  # recalculate the cross-section

def on_horizontal_slider(self, val):
    self.fraction = val / 100.0
    self.progressBar_1.setValue(val)
    self.SpinBox_PBar.setValue(val)
    self.updateGui()

def on_doubleSpinBox_X_valueChanged(self, val):
    self.axisX = val
    self.updateAxis()

def on_doubleSpinBox_Y_valueChanged(self, val):
    self.axisY = val
    self.updateAxis()

def on_doubleSpinBox_Z_valueChanged(self, val):
    self.axisZ = val
    self.updateAxis()

def on_SpinBox_PBar_valueChanged(self, val):
    self.progressBar_1.setValue(val)
    self.horizontalSlider.setValue(int(val))
    self.updateGui()

def onRadioButton(self, wasChecked):
    if self.radioButton_1.isChecked():
        self.cross_section_type = 1
    else:
        self.cross_section_type = 2
    self.updateGui()

#######################################

Find FreeCAD's root window

FreeCADRootWindow = FreeCADGui.getMainWindow()

Create the window and start it

myWidget = CrossSectionWindow()

The CrossSectionWindow will do all the work

}}

Example

Links

The forum discussion Posting a new macro

Version

ver 00.10 19/12/2020 : upgrade by Chris_G fix to exclude App.Part from input objects, see cross section macro does not work on bodies within a part container

ver 00.09 31/08/2019 : upgrade by g.becu adding line 334 #Sezione Dinamica

ver 00.08 04/07/2019 : upgrade replace Tab to Space by duke24 Macro cross_section update

ver 00.07 17/09/2017 : upgrade multiple objects with different colors by Gift

ver 00.06 06/09/2017 : upgrade by Gift see Optischer Schnitt durch Baugruppe, z.B. für Ventilgehäuse accept the multiple objects with different colors

ver 00.05 17/08/2017 : upgrade for 0.17 FreeCAD version by Sam see Sezione Dinamica


⏵ documentation index > Macro cross section

This page is retrieved from https://github.com/FreeCAD/FreeCAD-documentation/blob/main/wiki/Macro_cross_section.md

Get in touch!
Forum GitHub Mastodon Matrix IRC Gitter.im Discord Reddit Twitter Facebook LinkedIn

© The FreeCAD Team. Homepage image credits (top to bottom): ppemawm, r-frank, epileftric, regis, rider_mortagnais, bejant.

This project is supported by: , KiCad Services Corp. and other sponsors

GitHubImprove this page on GitHub