[Discussion] A different approach to Arch modelling (Arch Assembly?)

A forum dedicated to the Draft, Arch and BIM workbenches development.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
paullee
Veteran
Posts: 5136
Joined: Wed May 04, 2016 3:58 pm

Re: [Discussion] A different approach to Arch modelling (Arch Assembly?)

Post by paullee »

Looks cool 8-)
carlopav
Veteran
Posts: 2062
Joined: Mon Dec 31, 2018 1:49 pm
Location: Venice, Italy

Re: [Discussion] A different approach to BIM modelling (BIM Assembly?)

Post by carlopav »

yorik wrote: ping
I've started to clash my head on Ifc... It's quite hard.
Yoi did mention you were interested in separating it from Arch objects. So... How am I supposed to act? Shoud I add a preliminary support to the new wall and window using the current workflow? Should I start something different keeping prototype new objects as clean as possible?
What do you think?
follow my experiments on BIM modelling for architecture design
User avatar
onekk
Veteran
Posts: 6222
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: [Discussion] A different approach to Arch modelling (Arch Assembly?)

Post by onekk »

carlopav wrote: Wed Jun 10, 2020 8:33 pm

Code: Select all

#***************************************************************************
#*  Copyright (c) 2020 Carlo Dormeletti (onekk) carlo.dormeletti@yahoo.com *
#*                                                                         *
#*  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 program 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 program; if not, write to the Free Software    *
#*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307   *
#*  USA                                                                    *
#*                                                                         *
#***************************************************************************
"""Provide the window presets to be used in the Arch Opening object
"""
## @package window_presets
# \ingroup ARCH
# \brief Provide the window presets to be used in the Arch Opening object.

import FreeCAD
import FreeCADGui
from FreeCAD import Rotation, Vector

App = FreeCAD

# BEGIN DOC Settings
DEBUG = True
DBG_LOAD = False
DOC_NAME = "finestra"
# END DOC settings

EPS = 0.002

VZOR = App.Vector(0, 0, 0)
ROT0 = App.Rotation(0, 0, 0)
ROTX90 = App.Rotation(0, 0, 90)
ROTXN90 = App.Rotation(0, 0, -90)
ROTY90 = App.Rotation(0, 90, 0)
ROTZ180 = App.Rotation(180, 0, 0)
#Used to shorten most Placements
PL0 = App.Placement(VZOR, ROT0)

# DOCUMENT START HERE

# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Components

def frame_rectangular(tel_w, tel_h , tel_ww, tel_wh, tel_th, et=0):
    """ Return the shape of a rectangular frame.
    """
    import Part

    i_tel_w = tel_w - tel_ww * 2
    i_tel_h = tel_h - tel_wh * 2

    ep0 = (tel_w * -0.5, 0, 0)
    ep1 = (tel_w * 0.5, 0, 0)
    ep2 = (tel_w * 0.5, 0, tel_h)
    ep3 = (tel_w * -0.5, 0, tel_h)

    ip0 = (i_tel_w * -0.5, 0, tel_ww)
    ip1 = (i_tel_w * 0.5, 0, tel_ww)
    ip2 = (i_tel_w * 0.5, 0, tel_ww + i_tel_h)
    ip3 = (i_tel_w * -0.5, 0, tel_ww + i_tel_h)
  
    tel_b = (ep0, ep1, ip1, ip0, ep0)
    tel_bp = Part.makePolygon([Vector(*vtx) for vtx in tel_b])

    tel_r = (ep1, ep2, ip2, ip1, ep1)
    tel_rp = Part.makePolygon([Vector(*vtx) for vtx in tel_r])

    tel_t = (ep2, ep3, ip3, ip2, ep2)
    tel_tp = Part.makePolygon([Vector(*vtx) for vtx in tel_t])

    tel_l = (ep3, ep0, ip0, ip3, ep3)
    tel_lp = Part.makePolygon([Vector(*vtx) for vtx in tel_l])

    tel_fb = Part.makeFilledFace(tel_bp.Edges) 
    tel_fbs = tel_fb.extrude(Vector(0, tel_th, 0))

    tel_fr = Part.makeFilledFace(tel_rp.Edges) 
    tel_frs = tel_fr.extrude(Vector(0, tel_th, 0))
    
    tel_ft = Part.makeFilledFace(tel_tp.Edges) 
    tel_fts = tel_ft.extrude(Vector(0, tel_th, 0))

    tel_fl = Part.makeFilledFace(tel_lp.Edges) 
    tel_fls = tel_fl.extrude(Vector(0, tel_th, 0))    
    
    return Part.makeCompound([tel_fbs, tel_frs, tel_fts, tel_fls])


def glass(ea_w, ea_h, ef_w, ef_h, v_a, frame_th, glass_th): 
    """Return the shape of a rectangular glass panel.
    TODO: Check if a Part::Box is faster
    """
    import Part

    v_w = ea_w - ef_w + v_a * 2
    v_h = ea_h - ef_h + v_a * 2
    
    vp0 = (v_w * -0.5, 0, ef_w - v_a)
    vp1 = (v_w * 0.5, 0, ef_w  - v_a)
    vp2 = (v_w * 0.5, 0, ef_h - v_a + v_h)
    vp3 = (v_w * -0.5, 0, ef_h - v_a + v_h)
    
    glass_pt = (vp0, vp1, vp2, vp3, vp0)    
    glass_p = Part.makePolygon([Vector(*vtx) for vtx in glass_pt])
        
    glass_f = Part.makeFilledFace(glass_p.Edges) 
    glass_s = glass_f.extrude(Vector(0, glass_th, 0))

    return glass_s


def default_sill(opening_width, host_thickness, sill_thickness, front_protrusion, lateral_protrusion, inner_covering): 
    """Return the shape of a rectangular glass panel.
    TODO: Check if a Part::Box is faster
    """
    import Part

    sill_wid = opening_width + lateral_protrusion * 2
    sill_th = sill_thickness
    sill_len = host_thickness + front_protrusion - inner_covering
    sill = Part.makeBox(sill_wid, sill_len, sill_th)
    sill.Placement.Base = Vector(sill_wid * -0.5, host_thickness * -0.5 + inner_covering , sill_thickness * -1)

    return sill

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Windows

def window_single_pane(opening_th=300, opening_height=1400, opening_width=1200,
             frame_width=50, frame_th=50, glass_th=21, n_pan=1):
    """Return the shape of a full n_panes rectangular window.
    """
    import Part

    # permit to differentiate from the top-bottom and left right    
    frame_height = frame_width 
    
    # congruency check:
    frame_ov_wid = n_pan * (frame_width * 2) + frame_width * 2
    
    light_fact = (opening_width - frame_ov_wid) / opening_width 
    #print("FW LF >",frame_ov_wid, light_fact)

    # frame reduction 
    ef_w = frame_width * 2
    ef_h = frame_height * 2
    
    res_w = opening_width - ef_w     
    res_h = opening_height - ef_h
    
    # glass margin into the frame
    v_a = 0

    # TODO Adapt the warning to FreeCAD warning standard
    if  light_fact < 0.40 :
        print("Too Many panes in the window resulting in < 40% of the opening")
        return 

    # CREATE COMPONENTS
    components = []

    # CREATE FIXED FRAME
    components.append(frame_rectangular(opening_width, opening_height, frame_width, 
                   frame_height, frame_th))

    # CREATE OPENING PANELS
    if n_pan == 0:
        # TODO: If n_pan == 0 create a fixed window
        return

    if n_pan == 1:
        # Create a single pane window
        ea_w = res_w
        ea_h = res_h
        
        open_frame = frame_rectangular(ea_w, ea_h, frame_width,  frame_height, frame_th)
        open_frame.Placement = FreeCAD.Placement(Vector(0, 0, frame_height), ROT0)
        components.append(open_frame)

        glass_s = glass(ea_w, ea_h, ef_w, ef_h, v_a, frame_th, glass_th)  
        pl_v = FreeCAD.Placement(Vector(0, (frame_th - glass_th) * 0.5, 0), ROT0)        
        glass_s.Placement = pl_v

        components.append(glass_s)        

    elif n_pan > 1 and n_pan < 10: 
        # Create a multi pane window
        fact_w = res_w / n_pan
        
        loop = True
        cnt = 1
        while loop is True:
            if cnt > n_pan:
                break
            ea_w = fact_w
            adv_x = (cnt - 1) * fact_w
            ofx = (res_w * -0.5) + fact_w * 0.5 + adv_x
            ea_h = res_h

            open_frame = frame_rectangular(ea_w, ea_h, frame_width,  frame_height, frame_th)
            pl_ea = FreeCAD.Placement(Vector(ofx, 0, frame_height), ROT0)               
            open_frame.Placement = pl_ea
        
            components.append(open_frame)        
        
            glass_s = glass(ea_w, ea_h, ef_w, ef_h, v_a, frame_th, glass_th)  
            pl_v = FreeCAD.Placement(Vector(ofx, (frame_th - glass_th) * 0.5, 0), ROT0)        
            glass_s.Placement = pl_v

            components.append(glass_s)

            cnt += 1

    window = Part.makeCompound(components)
 
    return window

Code: Select all


import FreeCAD
import FreeCADGui
from FreeCAD import Rotation, Vector

App = FreeCAD
EPS = 0.002

VZOR = App.Vector(0, 0, 0)
ROT0 = App.Rotation(0, 0, 0)
I suppose that this things are sufficient, the other variables are needed for the rotation part, but in this code there is non need to rotate anything, so VZOR is for a Zero Vector and ROT0 stand for FreeCAD.Rotation(0,0,0) much more readable ans short.

maybe even :

Code: Select all

import FreeCADGui
Is not needed

Plus, maybe Part_box is more tailored, but you have to replace with a placement as the base using the my method is constructed directly around the Z axis.


But there are many way to do things, but as the Placement is the more difficult if you have to do multiple rotations, as a copy don't preserve the original placement, it may not be what you want.

Generally a placement is "retained" if you move the components in place before to make another operation like boolean operations, so if you plan to fuse or cut is better to move them prior in a manner that preserve your "reference point" in the place you are most comfortable to use in a second time.

Box is the more strange, apart from wedge, every other object use a more cmnfortable "reference point".

But maybe is only a matter of taste.

As using App in place of FreeCAD, this is not a good way, if you import FreeCAD, and then import:

Code: Select all

from FreeCAD import Rotation, Vector
non need to redefine:

Code: Select all

VZOR = App.Vector(0, 0, 0)
ROT0 = App.Rotation(0, 0, 0)
This is a habit generated from the code when it separate the interface importing somewhere in the initialization code:

Code: Select all

import FreeCAD as App
import FreeCADGui as Gui
I think this is a workaround to mantain the logical separation between FreeCAD that mostly if not entirely use OCCT and the internal definitions and FreeCADGui that is using Coin3D and is related to the Gui part, and to have more shorter code.

I think there is non need to reassign:

Code: Select all

App = FreeCAD
Another things why import Part module on every method?


Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
carlopav
Veteran
Posts: 2062
Joined: Mon Dec 31, 2018 1:49 pm
Location: Venice, Italy

Re: [Discussion] A different approach to Arch modelling (Arch Assembly?)

Post by carlopav »

onekk wrote: Sun Jun 14, 2020 3:41 pm ping
Hey there!
I've simplified it more: https://github.com/yorikvanhavre/BIM_Wo ... presets.py
It's not necessary to create a new placement and assign it when you just need to move something up by 5mm. Just change shape.Placement.Base.z :)
Part is imported on every module for lazy loading. We avoid importing big modules on the top of the file (cause they are loaded on startup), so BIM workbench loads faster (according to yorik).
follow my experiments on BIM modelling for architecture design
User avatar
onekk
Veteran
Posts: 6222
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: [Discussion] A different approach to Arch modelling (Arch Assembly?)

Post by onekk »

carlopav wrote: Sun Jun 14, 2020 4:23 pm
onekk wrote: Sun Jun 14, 2020 3:41 pm ping
Hey there!
I've simplified it more: https://github.com/yorikvanhavre/BIM_Wo ... presets.py
It's not necessary to create a new placement and assign it when you just need to move something up by 5mm. Just change shape.Placement.Base.z :)
Part is imported on every module for lazy loading. We avoid importing big modules on the top of the file (cause they are loaded on startup), so BIM workbench loads faster (according to yorik).

Code: Select all

# BEGIN DOC Settings
DEBUG = True
DBG_LOAD = False
DOC_NAME = "finestra"
# END DOC settings
This code is not useful anymore, it relates to "my way" of settings things.

Godd hint the "Placement.Base.".

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
User avatar
yorik
Founder
Posts: 13665
Joined: Tue Feb 17, 2009 9:16 pm
Location: Brussels
Contact:

Re: [Discussion] A different approach to Arch modelling (Arch Assembly?)

Post by yorik »

carlopav wrote: Sun Jun 14, 2020 4:23 pm Part is imported on every module for lazy loading. We avoid importing big modules on the top of the file (cause they are loaded on startup), so BIM workbench loads faster (according to yorik).
It's not really a big problem for the BIM WB, because you as a user choose to install it, so it doesn't harm every other FreeCAD user, but the BIM WB is really beginning to take time to load... Several seconds here. So I began to give it some optimizing.

That late loading is really important. It's a fundamental design decision of FreeCAD, and also matter of respect for other users too. We don't make loading time of others worse because we want something better for ourselves. We need to constantly keep optimizing FreeCAD. It's a complex and heavyweight application, and each little bit of additional weight here and there multiplies and makes things slower. Of course that is not just about late loading, but it has its part to play there. Many commercial apps use the late loading concept too.

I'm replying here for the other thread too where you complained about this @carlopav I understand everybody wants nicer code, but I don't think this should ever come at the cost of performance. Of course I agree the json module is lightweight and can go to the top. But some modules just cannot go to the top. And IMHO if we anyway can't get a clean, ideal solution where all imports are nicely organized to the top of the file, there is no really big gain in being picky here...

But I won't start a flame war over this either, if these things are so important to you guys, I'll take care of putting as much as possible to the top. But my opinion is that little by little we are harming overall responsiveness. and this will need some workaround at some point in the future
carlopav
Veteran
Posts: 2062
Joined: Mon Dec 31, 2018 1:49 pm
Location: Venice, Italy

Re: [Discussion] A different approach to Arch modelling (Arch Assembly?)

Post by carlopav »

yorik wrote: Wed Jun 17, 2020 9:20 am That late loading is really important.
+1!
I don't remember complaying about that :) (and I'm keeping this stile with BIM too)
follow my experiments on BIM modelling for architecture design
User avatar
yorik
Founder
Posts: 13665
Joined: Tue Feb 17, 2009 9:16 pm
Location: Brussels
Contact:

Re: [Discussion] A different approach to Arch modelling (Arch Assembly?)

Post by yorik »

Oh sorry, it was @vocx who complained, not you
User avatar
onekk
Veteran
Posts: 6222
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: [Discussion] A different approach to Arch modelling (Arch Assembly?)

Post by onekk »

Sorry for the intrusion, importing the Part module I think is not a big problem, it is the "base" ot FreeCAD, or not?

Not counting that every line that is not a comment is parsed and so it is using some time, maybe a very little time to be executed.

One caveat, is to time the execution, (only for testing pourpose), it could be done simply putting some var that store the actual time and then printout the difference from the preceding time, is very easy to do and to use and can reveal some bottleneck, maybe in some "plain" codes.

I think I have read something about python execution speed somewhere, but i don't remember well where, let me search and maybe we will find some hints.

First Hit could be useful?

https://wiki.python.org/moin/PythonSpee ... rmanceTips

There is some test for the import in a function versus the general import speaking in terms of performance under Import Statement Overhead

another find:

https://pybit.es/faster-python.html


Hope it will help

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
carlopav
Veteran
Posts: 2062
Joined: Mon Dec 31, 2018 1:49 pm
Location: Venice, Italy

Re: [Discussion] A different approach to Arch modelling (Arch Assembly?)

Post by carlopav »

onekk wrote: Wed Jun 17, 2020 5:13 pm importing the Part module I think is not a big problem, it is the "base" ot FreeCAD, or not?
I don't think so. It's just one module as another. :)
Freecad can run without the part module, but you will need it if you want to use OCC.
But you can perfectly want to use other libraries.
At least that's what i've understood.

Edit: So for example you may want to use a draft Text from the Draft module, that do not use Part. If the import of Part is at the beginning of just one of Draft modules, importing Draft will load Part, and this could slow down importing Draft for a user that do not want to use OCC shapes. Again, at least this is what i've understood :)
Last edited by carlopav on Wed Jun 17, 2020 9:37 pm, edited 1 time in total.
follow my experiments on BIM modelling for architecture design
Post Reply