Demonstrating coding abilities

Have some feature requests, feedback, cool stuff to share, or want to know where FreeCAD is going? This is the place.
Forum rules
Be nice to others! Read the FreeCAD code of conduct!
User avatar
amrit3701
Posts: 343
Joined: Mon Jun 13, 2016 5:37 pm

Demonstrating coding abilities

Post by amrit3701 »

Hi,

Is the bug fixing the only way to demonstrate coding abilities for GSoC? Is it acceptable if I submit a piece of code related to my proposed GSoC project "Rebar addon for FreeCAD"?

Regards,
Amritpal Singh
Github, Like my work, sponsor me!
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Demonstrating coding abilities

Post by ickby »

Hello,

bug fixing is one way, but doing some work for your proposal already is also welcome. We just like to see that you understand FreeCADs architecture, and that you are able to add code into the infrastructure.
User avatar
amrit3701
Posts: 343
Joined: Mon Jun 13, 2016 5:37 pm

Re: Demonstrating coding abilities

Post by amrit3701 »

ickby wrote: bug fixing is one way, but doing some work for your proposal already is also welcome. We just like to see that you understand FreeCADs architecture, and that you are able to add code into the infrastructure.
I have coded a fully parametric rectangular footing rebar mesh and sharing its Python code below as a proof of concept for my GSoC proposal:

Code: Select all

import ArchCommands,ArchComponent,FreeCAD
from FreeCAD import Vector, Rotation
import Draft
import DraftGeomUtils



def _make_circular_rebar(points, dia, rebars):
    """ This function takes the points of the lines, diameter of the rebar
        and then return all the generated rebars. """
    lines = []
    lines.append(Part.Line(points[1],points[0]))
    spath = Part.Shape(lines)
    edge = Part.__sortEdges__(spath.Edges)
    wpath = Part.Wire(edge)
    wire = Part.Wire(spath)
    bpoint = points[0]
    bvec = points[1].sub(points[0]).normalize()
    circle = Part.makeCircle(dia/2,bpoint,bvec)
    circle = Part.Wire(circle)
    rebars.append(wire.makePipeShell([circle],True,False,2))
    return rebars



class _rectangular_footing_mesh(ArchComponent.Component):
    def __init__(self,obj):
        # Import ArchCompent properties.
        ArchComponent.Component.__init__(self,obj)
        # Initialize all the parameters of rectangular footing mesh.
        obj.addProperty("App::PropertyDistance", "DiaX", "Rebars along X-axis", "Diameter of rebars").DiaX = 20
        obj.addProperty("App::PropertyQuantity", "BarsX", "Rebars along X-axis", "Number of rebars").BarsX = 10
        obj.addProperty("App::PropertyDistance", "SpacingX", "Rebars along X-axis", "Spacing between rebars").SpacingX = 100
        obj.addProperty("App::PropertyDistance", "OffsetX", "Rebars along X-axis", "Edge cover from top rebars").OffsetX = 50
        obj.addProperty("App::PropertyDistance", "DiaY", "Rebars along Y-axis", "Diameter of rebar").DiaY = 12
        obj.addProperty("App::PropertyQuantity", "BarsY", "Rebars along Y-axis", "Number of rebars").BarsY = 10
        obj.addProperty("App::PropertyDistance", "Spacing2", "Rebars along Y-axis", "Spacing between rebars").Spacing2 = 150
        obj.addProperty("App::PropertyDistance", "OffsetY", "Rebars along Y-axis", "Edge cover from bottom rebars").OffsetY = 50


    def execute(self,obj):
        if self.clone(obj):
            return

        # Calculating the length of bottom and top rebars.
        length1 = 2*obj.OffsetY+(obj.Spacing2*(int(obj.BarsY)-1))
        length2 = 2*obj.OffsetX+(obj.SpacingX*(int(obj.BarsX)-1))

        import Part
        bottom_rebar_pts = []
        upper_rebar_pts = []

        # Calculating the distance of the second bottom rebar from origin.
        spacing_points = obj.OffsetX + obj.SpacingX

        # Calculating all value of points in space of bottom rebar and append it into bottom_rebar_pts array.
        bottom_rebar_pts.append([Vector(0, obj.OffsetX,0), Vector(length1, obj.OffsetX, 0)])
        for i in range(int(obj.BarsX)-1):
            bottom_rebar_pts.append([Vector(0, spacing_points, 0), Vector(length1, spacing_points, 0)])
            # Increment the spacing_points by spacing present between the rebars.
            spacing_points += obj.SpacingX

        # Calculating the distance of the second top rebar from origin.
        spacing_points = obj.OffsetY + obj.Spacing2
        # Calculating all value of points in space of top rebar and append it into bottom_rebar_pts array.
        upper_rebar_pts.append([Vector(obj.OffsetY, 0, obj.DiaX/2+obj.DiaY/2), Vector(obj.OffsetY, length2, obj.DiaX/2+obj.DiaY/2)])
        for i in range(int(obj.BarsY)-1):
            upper_rebar_pts.append([Vector(spacing_points, 0, obj.DiaX/2+obj.DiaY/2), Vector(spacing_points, length2, obj.DiaX/2+obj.DiaY/2)])
            spacing_points += obj.Spacing2

        bars = []
        # Transform points of rebar to 3D circular shape.
        for i in bottom_rebar_pts:
            _make_circular_rebar(i, obj.DiaX, bars)
        # Transform points of rebar to 3D circular shape.
        for i in upper_rebar_pts:
            _make_circular_rebar(i, obj.DiaY, bars)

        # Transform all rebars into a single entity.
        finalshape = Part.makeCompound(bars)
        obj.Shape = finalshape



class _ViewProviderRebar(ArchComponent.ViewProviderComponent):
    def __init__(self,vobj):
        ArchComponent.ViewProviderComponent.__init__(self,vobj)
        # Initializing the color to rebars
        vobj.ShapeColor = (0.67,0.00,0.00)

    def getIcon(self):
        import Arch_rc
        return ":/icons/Arch_Rebar_Tree.svg"


if __name__=="__main__":
    obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Rectangular footing mesh")
    _rectangular_footing_mesh(obj)

    if FreeCAD.GuiUp:
        _ViewProviderRebar(obj.ViewObject)
        FreeCAD.ActiveDocument.recompute()
Below is the output of above code when you run in FreeCAD Python console window:
rectangular_footing.png
rectangular_footing.png (193.82 KiB) Viewed 2418 times
Amritpal Singh
Github, Like my work, sponsor me!
User avatar
yorik
Founder
Posts: 13640
Joined: Tue Feb 17, 2009 9:16 pm
Location: Brussels
Contact:

Re: Demonstrating coding abilities

Post by yorik »

Ok this looks good to me...
This script touches most of what you'll need during the GSOC project
User avatar
cnirbhay
Posts: 115
Joined: Wed Aug 17, 2016 4:24 pm

Re: Demonstrating coding abilities

Post by cnirbhay »

Wow! That's impressive @Amrit3701. Glad to see your dedication that you've started doing some workout with the FreeCAD architecture. All the best for this project. I'll be happy if this thing gets selected in GSoC, that would boost you with an extra motivation to work more efficiently. :-)
User avatar
bernd
Veteran
Posts: 12849
Joined: Sun Sep 08, 2013 8:07 pm
Location: Zürich, Switzerland
Contact:

Re: Demonstrating coding abilities

Post by bernd »

yorik wrote:Ok this looks good to me...
This script touches most of what you'll need during the GSOC project
+1

BTW: I get an error on the code ...

Code: Select all

21Standard_TypeMismatch TopoDS::Vertex
Traceback (most recent call last):
  File "<input>", line 49, in execute
  File "<input>", line 7, in _make_circular_rebar
<class 'Part.OCCError'>: 21Standard_TypeMismatch TopoDS::Vertex
OS: Debian GNU/Linux 8.7 (jessie)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.17.10674 (Git)
Build type: Unknown
Branch: master
Hash: 78d8272d771eb58fff1955ecdde080a639d95b94
Python version: 2.7.9
Qt version: 4.8.6
Coin version: 4.0.0a
OCC version: 7.0.0
User avatar
amrit3701
Posts: 343
Joined: Mon Jun 13, 2016 5:37 pm

Re: Demonstrating coding abilities

Post by amrit3701 »

bernd wrote: BTW: I get an error on the code ...

Code: Select all

21Standard_TypeMismatch TopoDS::Vertex
Traceback (most recent call last):
  File "<input>", line 49, in execute
  File "<input>", line 7, in _make_circular_rebar
<class 'Part.OCCError'>: 21Standard_TypeMismatch TopoDS::Vertex
Hi Bernd,

This script is not working on latest version of FreeCAD (0.17) but it working fine on all later versions of FreeCAD. Part.__sortEdges__(spath.Edges) is the key behind this error.

BTW, for demo, you should try it on FreeCAD (0.16) version.:)

Regards,
Amritpal Singh
Github, Like my work, sponsor me!
User avatar
amrit3701
Posts: 343
Joined: Mon Jun 13, 2016 5:37 pm

Re: Demonstrating coding abilities

Post by amrit3701 »

yorik wrote:Ok this looks good to me...
This script touches most of what you'll need during the GSOC project
I am made the dialog box for straight rebar. To run this code you just copy and paste in FreeCAD python console.

Code: Select all

from PyQt4 import QtCore, QtGui

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)

class Ui_Straight_rebar_Dialog(object):
    def setupUi(self, Straight_rebar_Dialog):
        self.window = Straight_rebar_Dialog

        Straight_rebar_Dialog.setObjectName(_fromUtf8("Straight_rebar_Dialog"))
        Straight_rebar_Dialog.resize(509, 363)
        self.buttonBox = QtGui.QDialogButtonBox(Straight_rebar_Dialog)
        self.buttonBox.setGeometry(QtCore.QRect(132, 310, 191, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
        self.side_cover = QtGui.QLineEdit(Straight_rebar_Dialog)
        self.side_cover.setGeometry(QtCore.QRect(240, 52, 113, 27))
        self.side_cover.setObjectName(_fromUtf8("side_cover"))
        self.front_cover = QtGui.QLineEdit(Straight_rebar_Dialog)
        self.front_cover.setGeometry(QtCore.QRect(240, 121, 113, 27))
        self.front_cover.setObjectName(_fromUtf8("front_cover"))
        self.spacing_label = QtGui.QLabel(Straight_rebar_Dialog)
        self.spacing_label.setGeometry(QtCore.QRect(177, 259, 67, 17))
        self.spacing_label.setObjectName(_fromUtf8("spacing_label"))
        self.amount = QtGui.QSpinBox(Straight_rebar_Dialog)
        self.amount.setGeometry(QtCore.QRect(240, 222, 48, 27))
        self.amount.setObjectName(_fromUtf8("amount"))
        self.amount.setEnabled(False)
        self.front_cover_label = QtGui.QLabel(Straight_rebar_Dialog)
        self.front_cover_label.setGeometry(QtCore.QRect(153, 125, 91, 17))
        self.front_cover_label.setObjectName(_fromUtf8("front_cover_label"))
        self.diameter = QtGui.QLineEdit(Straight_rebar_Dialog)
        self.diameter.setGeometry(QtCore.QRect(240, 157, 113, 27))
        self.diameter.setObjectName(_fromUtf8("diameter"))
        self.amount_label = QtGui.QLabel(Straight_rebar_Dialog)
        self.amount_label.setGeometry(QtCore.QRect(175, 226, 67, 17))
        self.amount_label.setObjectName(_fromUtf8("amount_label"))
        self.spacing = QtGui.QLineEdit(Straight_rebar_Dialog)
        self.spacing.setGeometry(QtCore.QRect(240, 255, 113, 27))
        self.spacing.setObjectName(_fromUtf8("spacing"))
        self.spacing.setEnabled(False)
        self.diameter_label = QtGui.QLabel(Straight_rebar_Dialog)
        self.diameter_label.setGeometry(QtCore.QRect(166, 159, 81, 20))
        self.diameter_label.setObjectName(_fromUtf8("diameter_label"))
        self.amount_radio = QtGui.QRadioButton(Straight_rebar_Dialog)
        self.amount_radio.setGeometry(QtCore.QRect(147, 193, 117, 22))
        self.amount_radio.setObjectName(_fromUtf8("amount_radio"))
        self.spacing_radio = QtGui.QRadioButton(Straight_rebar_Dialog)
        self.spacing_radio.setGeometry(QtCore.QRect(237, 193, 117, 22))
        self.spacing_radio.setObjectName(_fromUtf8("spacing_radio"))
        self.side_cover_label = QtGui.QLabel(Straight_rebar_Dialog)
        self.side_cover_label.setGeometry(QtCore.QRect(159, 57, 71, 17))
        self.side_cover_label.setObjectName(_fromUtf8("side_cover_label"))
        self.bottom_cover = QtGui.QLineEdit(Straight_rebar_Dialog)
        self.bottom_cover.setGeometry(QtCore.QRect(240, 86, 113, 27))
        self.bottom_cover.setObjectName(_fromUtf8("bottom_cover"))
        self.bottom_cover_label = QtGui.QLabel(Straight_rebar_Dialog)
        self.bottom_cover_label.setGeometry(QtCore.QRect(137, 90, 101, 17))
        self.bottom_cover_label.setObjectName(_fromUtf8("bottom_cover_label"))
        self.main_heading = QtGui.QLabel(Straight_rebar_Dialog)
        self.main_heading.setGeometry(QtCore.QRect(188, 12, 121, 31))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.main_heading.setFont(font)
        self.main_heading.setLineWidth(1)
        self.main_heading.setObjectName(_fromUtf8("main_heading"))

        self.retranslateUi(Straight_rebar_Dialog)
        self.amount_radio.clicked.connect(self.amount_radio_clicked)
        self.spacing_radio.clicked.connect(self.spacing_radio_clicked)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), self.accept)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), self.reject)
        QtCore.QMetaObject.connectSlotsByName(Straight_rebar_Dialog)

    def retranslateUi(self, Straight_rebar_Dialog):
        Straight_rebar_Dialog.setWindowTitle(_translate("Straight_rebar_Dialog", "Dialog", None))
        self.spacing_label.setText(_translate("Straight_rebar_Dialog", "Spacing", None))
        self.front_cover_label.setText(_translate("Straight_rebar_Dialog", "Front cover", None))
        self.amount_label.setText(_translate("Straight_rebar_Dialog", "Amount", None))
        self.diameter_label.setText(_translate("Straight_rebar_Dialog", "Diameter", None))
        self.amount_radio.setText(_translate("Straight_rebar_Dialog", "Amount", None))
        self.spacing_radio.setText(_translate("Straight_rebar_Dialog", "Spacing", None))
        self.side_cover_label.setText(_translate("Straight_rebar_Dialog", "Side cover", None))
        self.bottom_cover_label.setText(_translate("Straight_rebar_Dialog", "Bottom cover", None))
        self.main_heading.setText(_translate("Straight_rebar_Dialog", "Fill all the values", None))

    def accept(self):
        self.window.close()
        FreeCAD.Console.PrintMessage("Done!\n")

    def reject(self):
        self.window.close()
        FreeCAD.Console.PrintMessage("Terminate!\n")

    def amount_radio_clicked(self):
        self.spacing.setEnabled(False)
        self.amount.setEnabled(True)

    def spacing_radio_clicked(self):
        self.amount.setEnabled(False)
        self.spacing.setEnabled(True)



class dialog():
   def __init__(self):
       self.d = QtGui.QWidget()
       self.ui = Ui_Straight_rebar_Dialog()
       self.ui.setupUi(self.d)
       self.d.show()

dialog()
Tell me if any improvement is required in the dialog box. Currently, I am working for reinforcement of straight rebar using sketcher.

Regards,
Amritpal Singh
Github, Like my work, sponsor me!
User avatar
yorik
Founder
Posts: 13640
Joined: Tue Feb 17, 2009 9:16 pm
Location: Brussels
Contact:

Re: Demonstrating coding abilities

Post by yorik »

Wouldn't it be interesting to use the Task panel? This gives less clutter to the screen and allows, for example, to more easily pick geometry while the dialog is open

Also, your code seems to be generated from pyuic... It is advisable to keep your ui design as a ui file, otherwise you'll get into a lot of hassle when you want to change something in it.

Check src/Mod/Arch/ArchServer.py, there a re a couple of examples there to do these two things...
User avatar
amrit3701
Posts: 343
Joined: Mon Jun 13, 2016 5:37 pm

Re: Demonstrating coding abilities

Post by amrit3701 »

yorik wrote:Wouldn't it be interesting to use the Task panel? This gives less clutter to the screen and allows, for example, to more easily pick geometry while the dialog is open
Yes, I also think the Task panel is the better choice than dialog box. It will enrich user experience.
yorik wrote: Also, your code seems to be generated from pyuic... It is advisable to keep your ui design as a ui file, otherwise you'll get into a lot of hassle when you want to change something in it.

Check src/Mod/Arch/ArchServer.py, there a re a couple of examples there to do these two things...
Ok, now I separated my UI file from Python code. Here is my code:
https://github.com/amrit3701/FreeCAD-Reinforcement
task_panel.png
task_panel.png (150.71 KiB) Viewed 2125 times
Tell me if any improvement will require in the UI. :)

Regards,
Amritpal Singh
Github, Like my work, sponsor me!
Post Reply