best way to draw 2D steel column view

A forum dedicated to the Draft, Arch and BIM workbenches development.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
ebrahim raeyat
Posts: 621
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

best way to draw 2D steel column view

Post by ebrahim raeyat »

Hi @all, I don't know that this is related post to this topic, but my question is:

* I want to draw this steel columns in format of DXF. I take some approach, but I want to know your opinions:

1- draw section of each story and then extrude it. then use techdraw WB to obtain 2D viewing of it, then create text label for each item.
2- draw it 2D basically: use centerline of section as sketch and then offset this by Draft WB and for plates, draw it as rectangle, but this way I must calculate myself, extended line and dashed line start and end points.
3- draw without freecad: user can not modify model interactively.

Personally I prefer 1st method. Thanks
columntype.png
columntype.png (43.47 KiB) Viewed 3392 times
column.png
column.png (18.74 KiB) Viewed 3392 times
section.png
section.png (15.32 KiB) Viewed 3392 times
User avatar
ebrahim raeyat
Posts: 621
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

Re: best way to draw 2D steel column view

Post by ebrahim raeyat »

I write this code for drawing section, but I want to assign all objects as Shape of Section object:

Code: Select all

import FreeCAD
import Part
import ArchProfile
import Draft

class PartFeature:
    def __init__(self, obj):
        obj.Proxy = self


class Section(PartFeature):
    def __init__(self, obj):
        PartFeature.__init__(self, obj)
        self.set_properties(obj)

    def set_properties(self, obj):
        self.Type = "Section"
        
        if not hasattr(obj, "n"):
            obj.addProperty(
                "App::PropertyInteger",
                "n",
                "section",
            )

        if not hasattr(obj, "size"):
            obj.addProperty(
                "App::PropertyInteger",
                "size",
                "section",
            )

        if not hasattr(obj, "flange_plate"):
            obj.addProperty(
                "App::PropertyIntegerList",
                "flange_plate",
                "section",
            )

        if not hasattr(obj, "web_plate"):
            obj.addProperty(
                "App::PropertyIntegerList",
                "web_plate",
                "section",
            )

    def execute(self, obj):
        sectionType = "IPE"
        sectionSize = obj.size
        baseSectionType = "H"
        bf = 90
        d = 180
        tf = 8
        tw = 6
        dist = 0
        doc = App.ActiveDocument
        group=doc.addObject("App::DocumentObjectGroup",obj.Name)
        s1 = ArchProfile.makeProfile([0, sectionType, sectionType + '_000', baseSectionType ,bf, d, tw, tf])
        gui = Gui.ActiveDocument
        gui.getObject(s1.Label).LineColor = (1.0, 0.0, 0.0)
        gui.getObject(s1.Label).DisplayMode = "Wireframe"
        ipe = doc.getObjectsByLabel(s1.Label)[0]
        group.addObject(s1)
        deltax = bf + dist
        if obj.n == 3:
            Draft.move(ipe, App.Vector(deltax, 0, 0), copy=False)
            s2 = Draft.move(ipe, App.Vector(-deltax, 0, 0), copy=True)
            s3 = Draft.move(ipe, App.Vector(-2 * deltax, 0, 0), copy=True)
            group.addObjects([s2, s3])

        if obj.n == 2:
            Draft.move(ipe, App.Vector(deltax / 2, 0, 0), copy=False)
            s2 = Draft.rotate(ipe, 180, center=App.Vector(0, 0, 0), copy=True)
            group.addObject(s2)

        if obj.flange_plate:
            width = obj.flange_plate[0]
            height = obj.flange_plate[1]
            y = d + height / 2
            p3 = App.Vector(0, y, 0)
            plt = ArchProfile.makeProfile([0, 'PlateT', 'PlateT' + '_000', 'R' , width, height])
            gui.getObject(plt.Label).LineColor = (0.0, 0.0, 1.0)
            gui.getObject(plt.Label).DisplayMode = "Wireframe"
            Draft.move(doc.PlateT_000, p3)
            plb = Draft.rotate(doc.PlateT_000, 180, center=App.Vector(0, 0, 0), copy=True)
            group.addObjects([plt, plb])

        if obj.web_plate:
            width = obj.web_plate[0]
            height = obj.web_plate[1]
            x = ipe.Shape.BoundBox.Center.x + (ipe.WebThickness.Value + height) / 2
            p6 = App.Vector(x, 0, 0)
            plwr = ArchProfile.makeProfile([0, 'PlateWR', 'PlateWR' + '_000', 'R' , height, width])
            gui.getObject(plwr.Label).LineColor = (0.0, 1.0, 0.0)
            gui.getObject(plwr.Label).DisplayMode = "Wireframe"
            Draft.move(doc.PlateWR_000, p6)
            plwl = Draft.rotate(doc.PlateWR_000, 180, center=App.Vector(0, 0, 0), copy=True)
            group.addObjects([plwr, plwl])

        obj.Shape = Part.makeCompound([i.Shape for i in group.Group])

def decompose_section_name(name):
    name = name.upper()
    n = int(name[0])
    size = int(name[4:6])
    fi = name.find("PL")
    wi = name.find("W")
    if fi != -1:
        if wi == -1:
            flang_plate = name[fi:]
        else:
            flang_plate = name[fi: wi]
        flang_plate = flang_plate.lstrip("PL")
        flang_plate = flang_plate.split("X")
        flang_plate_dim = [int(i) for i in flang_plate]
    else:
        flang_plate_dim = []
    if wi != -1:
        web_plate = name[wi:]
        web_plate = web_plate.lstrip("W")
        web_plate = web_plate.split("X")
        web_plate_dim = [int(i) for i in web_plate]
    else:
        web_plate_dim = []

    return(n, size, flang_plate_dim, web_plate_dim)
    
    
def make_section(name):
    n, size, flange_plate, web_plate = decompose_section_name(name)
    obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "section")
    Section(obj)
    obj.Label = name
    obj.n = n
    obj.size = size
    obj.flange_plate = flange_plate
    obj.web_plate = web_plate
    FreeCAD.ActiveDocument.recompute()

make_section("3IPE18pl200x20w100x5")
        
Bance
Veteran
Posts: 4256
Joined: Wed Feb 11, 2015 3:00 pm
Location: London

Re: best way to draw 2D steel column view

Post by Bance »

Have you tried Dodo WB from addon manager?
User avatar
ebrahim raeyat
Posts: 621
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

Re: best way to draw 2D steel column view

Post by ebrahim raeyat »

Bance wrote: Mon Aug 17, 2020 2:34 pm Have you tried Dodo WB from addon manager?
Thanks a lot, I had been search and find Flamingo first, but early I found that it is for python2 and skipped it. But, Dodo!! Seems good for now.

BTW, I want to do this by python script. Now, do you guys have any new suggestions?
User avatar
ebrahim raeyat
Posts: 621
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

Re: best way to draw 2D steel column view

Post by ebrahim raeyat »

I created Section object, this is my script, Although the FreeCAD had been created profile object and I didn't understand how can I give shape of profile(with Shape.copy()?? But when I remove Profile, my shape disappear) to assign Section Object, I copy source code from Arch.makeProfile in my code, I copy create_ipe and create_plate method from Arch WB to get the shape of profile directly not profile object:

Code: Select all

import FreeCAD, FreeCADGui
import Part
from FreeCAD import Vector
import ArchProfile
from Arch import makeStructure
import Draft
import csv
from os.path import join, dirname, abspath
from columnTypeFunctions import *


class Section:
    def __init__(self, obj):
        obj.Proxy = self
        self.set_properties(obj)

    def set_properties(self, obj):
        self.Type = "Section"
        
        if not hasattr(obj, "n"):
            obj.addProperty(
                "App::PropertyInteger",
                "n",
                "section",
            )

        if not hasattr(obj, "size"):
            obj.addProperty(
                "App::PropertyInteger",
                "size",
                "section",
            )

        # if not hasattr(obj, "core_section"):
        #     obj.addProperty(
        #         "App::PropertyLinkList",
        #         "core_section",
        #         "Components",
        #         )

        # if not hasattr(obj, "flange_plate"):
        #     obj.addProperty(
        #         "App::PropertyLinkList",
        #         "flange_plate",
        #         "Components",
        #         )

        # if not hasattr(obj, "web_plate"):
        #     obj.addProperty(
        #         "App::PropertyLinkList",
        #         "web_plate",
        #         "Components",
        #         )

        if not hasattr(obj, "flange_plate_size"):
            obj.addProperty(
                "App::PropertyIntegerList",
                "flange_plate_size",
                "section",
            )

        if not hasattr(obj, "web_plate_size"):
            obj.addProperty(
                "App::PropertyIntegerList",
                "web_plate_size",
                "section",
            )

        if not hasattr(obj, "outer_wires"):
            obj.addProperty(
                "App::PropertyLinkList",
                "outer_wires",
                "section",
                )

        if not hasattr(obj, "dist"):
            obj.addProperty(
                "App::PropertyFloat",
                "dist",
                "section",
                )

        if not hasattr(obj, "level"):
            obj.addProperty(
                "App::PropertyFloat",
                "level",
                "section",
                )


    def execute(self, obj):
        name = ""
        shapes = []
        sectionSize = obj.size
        sectionType = "IPE"
        file_name = "Section_IPE.csv"
        with open(join(dirname(abspath(__file__)),"table",file_name),'r') as f:
            reader=csv.DictReader(f,delimiter=';')
            for row in reader:
                if row['SSIZE'] == f"IPE{sectionSize * 10}":
                    bf = float(row["BF"])
                    d = float(row["D"])
                    tw = float(row["TW"])
                    tf = float(row["TF"])
                    break

        dist = obj.dist
        doc = FreeCAD.ActiveDocument
        ipe = create_ipe(bf, d, tw, tf)
        deltax = bf + dist
        if obj.n == 3:
            ipe.Placement.Base.x = deltax
            ipe2 = ipe.copy()
            ipe2.Placement.Base.x = 0
            ipe3 = ipe.copy()
            ipe3.Placement.Base.x = -deltax
            # ipe2 = Draft.move(ipe, FreeCAD.Vector(-deltax, 0, 0), copy=True)
            # ipe3 = Draft.move(ipe, FreeCAD.Vector(-2 * deltax, 0, 0), copy=True)
            shapes.extend([ipe, ipe2, ipe3])
            name += f"3{sectionType}{sectionSize}"

        if obj.n == 2:
            ipe.Placement.Base.x = deltax / 2
            ipe2 = ipe.copy()
            ipe2.Placement.Base.x = -deltax / 2
            name += f"2{sectionType}{sectionSize}"
            shapes.extend([ipe, ipe2])

        if obj.flange_plate_size:
            width = obj.flange_plate_size[0]
            height = obj.flange_plate_size[1]
            y = (d + height) / 2
            plt = create_plate(width, height)
            plt.Placement.Base.y = y
            # plt.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
            # gui.getObject(plt.Label).DisplayMode = "Wireframe"
            plb = plt.copy()
            plb.Placement.Base.y = -y
            # group.addObjects([plt, plb])
            shapes.extend([plt, plb])
            name += f"PL{width}X{height}"

        if obj.web_plate_size:
            width = obj.web_plate_size[0]
            height = obj.web_plate_size[1]
            # x = ipe.Shape.BoundBox.Center.x + (ipe.WebThickness.Value + height) / 2
            x = ipe.Placement.Base.x + (tw + height) / 2

            plwr = create_plate(height, width)
            plwr.Placement.Base.x = x

            # gui.getObject(plwr.Label).ShapeColor = (0.0, 1.0, 0.0)
            # gui.getObject(plwr.Label).DisplayMode = "Wireframe"
            plwl = plwr.copy()
            plwl.Placement.Base.x = -x
            # group.addObjects([plwr, plwl])
            shapes.extend([plwr, plwl])
            name += f"W{width}X{height}"

        Components = Part.makeCompound(shapes)
        obj.Shape = Components
        obj.Placement.Base.z = obj.level
        # for o in (obj.core_section + obj.flange_plate + obj.web_plate):
        #     hide(o)
        #     print(o.Label)
        #     FreeCAD.ActiveDocument.removeObject(o.Label)
        obj.Label = name
        

def create_ipe(width, height, tw, tf):
    import Part
    p1 = Vector(-width/2,-height/2,0)
    p2 = Vector(width/2,-height/2,0)
    p3 = Vector(width/2,(-height/2)+tf,0)
    p4 = Vector(tw/2,(-height/2)+tf,0)
    p5 = Vector(tw/2,height/2-tf,0)
    p6 = Vector(width/2,height/2-tf,0)
    p7 = Vector(width/2,height/2,0)
    p8 = Vector(-width/2,height/2,0)
    p9 = Vector(-width/2,height/2-tf,0)
    p10 = Vector(-tw/2,height/2-tf,0)
    p11 = Vector(-tw/2,(-height/2)+tf,0)
    p12 = Vector(-width/2,(-height/2)+tf,0)
    p = Part.makePolygon([p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p1])
    p = Part.Face(p)
    return p

def create_plate(width, height):
    import Part
    p1 = Vector(-width/2,-height/2,0)
    p2 = Vector(width/2,-height/2,0)
    p3 = Vector(width/2,height/2,0)
    p4 = Vector(-width/2,height/2,0)
    p = Part.makePolygon([p1,p2,p3,p4,p1])
    p = Part.Face(p)
    return p    

        # for i, section in enumerate(obj.sections):
        #     if i > max_index:
        #         return
        #     height = obj.levels[i+1] - obj.levels[i]
class ViewProviderSection:

    "A View Provider for the Section object"

    def __init__(self, vobj):
        vobj.Proxy = self

    def attach(self, obj):
        ''' Setup the scene sub-graph of the view provider, this method is mandatory '''
        return

    def updateData(self, fp, prop):
        ''' If a property of the handled feature has changed we have the chance to handle this here '''
        return

    def getDisplayModes(self, obj):
        ''' Return a list of display modes. '''
        modes = []
        return modes

    def getDefaultDisplayMode(self):
        ''' Return the name of the default display mode. It must be defined in getDisplayModes. '''
        return "Shaded"

    def setDisplayMode(self, mode):
        ''' Map the display mode defined in attach with those defined in getDisplayModes.
        Since they have the same names nothing needs to be done. This method is optional.
        '''
        return mode

    def onChanged(self, vp, prop):
        ''' Print the name of the property that has changed '''
        FreeCAD.Console.PrintMessage("Change View property: " + str(prop) + "\n")




def make_section(name, dist=0, level=0):
    # for o in FreeCAD.ActiveDocument.Objects:
    #     if o.Label == name.upper():
    #         return
    n, size, flange_plate_size, web_plate_size = decompose_section_name(name)
    FreeCAD.Console.PrintMessage(f"{n}, {size}, {flange_plate_size}, {web_plate_size}")
    obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython", "section")
    Section(obj)
    ViewProviderSection(obj.ViewObject)
    obj.Label = name
    obj.n = n
    obj.size = size
    obj.flange_plate_size = flange_plate_size
    obj.web_plate_size = web_plate_size
    obj.dist = dist
    obj.level = level
    FreeCAD.ActiveDocument.recompute()
    FreeCAD.ActiveDocument.recompute()
    return obj

if __name__ == '__main__':
    make_section("3IPE18pl200x10w130x5")
    make_section("3IPE18pl200x10", 0, 3000)

my question:
how can I use Arch.makeProfile obj and only give the shape of object only, not creating it in ActiveDocument?
User avatar
ebrahim raeyat
Posts: 621
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

Re: best way to draw 2D steel column view

Post by ebrahim raeyat »

If I want to simplify my question, I create a section object, then create an IPE object and want to assign shape of IPE to section object and remove the IPE:

Code: Select all

import FreeCAD
import Arch

obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython", "section")
ipe = Arch.makeProfile([0, "IPE", "IPE", "H", 100, 200, 5, 8])
obj.Shape = ipe.Shape.copy()
If I add this line nothing change:
obj.Proxy = 0
or if I add ViewProvider() to section object.
User avatar
ebrahim raeyat
Posts: 621
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

Re: best way to draw 2D steel column view

Post by ebrahim raeyat »

Also, for creating Steel Column from sections, I want to assign my structures as Shape of ColumnType object:
ct.png
ct.png (59.64 KiB) Viewed 3132 times
User avatar
ebrahim raeyat
Posts: 621
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

Re: best way to draw 2D steel column view

Post by ebrahim raeyat »

ebrahim raeyat wrote: Sat Aug 22, 2020 11:51 am Also, for creating Steel Column from sections, I want to assign my structures as Shape of ColumnType object:

ct.png
thanks, I found it from dodo WB code, it was claimChildren method of ViewProvider :lol:
User avatar
ebrahim raeyat
Posts: 621
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

Re: best way to draw 2D steel column view

Post by ebrahim raeyat »

Hi @all. I completed code for creating columns for various type of column section in plan and elevation. Now I want to obtain 2D view from 3d column object. I want to use TechDraw WB. is there another solutions? If @"Suraj Dadral" can help. Thanks
col.png
col.png (27.42 KiB) Viewed 2651 times
this is my github code.
User avatar
ebrahim raeyat
Posts: 621
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

Re: best way to draw 2D steel column view

Post by ebrahim raeyat »

I finally finished this task. This is some example of output file with ezdxf library:

with some essential hidden lines:
col_hid.png
col_hid.png (11.28 KiB) Viewed 2537 times
without hidden line:
col_nothid.png
col_nothid.png (9.23 KiB) Viewed 2537 times
col_all.png
col_all.png (40.1 KiB) Viewed 2537 times
colAll_freecad.png
colAll_freecad.png (26.37 KiB) Viewed 2537 times
Post Reply