The wires of the faces of eg a box are not closed ?

Need help, or want to share a macro? Post here!
beamer146
Posts: 38
Joined: Sun Nov 24, 2013 12:17 pm

The wires of the faces of eg a box are not closed ?

Postby beamer146 » Mon Jan 13, 2014 8:51 pm

Hi,

I am running into some unexpected results when using wires.
I now think the root of the problem is that apparently the faces of my solid objects (such as eg a box created with makeBox) consist of a wire that is not closed.

Code: Select all

>>> b=Part.makeBox(2,3,4)
>>> b.Faces[1].Wires
[<Wire object at 0x760f8f0>]
>>> b.Faces[1].Wires[0].Vertexes
[<Vertex object at 0x5b7d8a0>, <Vertex object at 0x1e45190>, <Vertex object at 0x6b9b670>, <Vertex object at 0x5923c80>]
>>> b.Faces[1].Wires[0].Vertexes[0].Point
Vector (2.0, 0.0, 4.0)
>>> b.Faces[1].Wires[0].Vertexes[1].Point
Vector (2.0, 0.0, 0.0)
>>> b.Faces[1].Wires[0].Vertexes[2].Point
Vector (2.0, 3.0, 4.0)
>>> b.Faces[1].Wires[0].Vertexes[3].Point
Vector (2.0, 3.0, 0.0)
>>> b.Faces[1].Wires[0].isClosed()
False
>>> b.Faces[1].isValid()
True
Since a closed wire is needed to create a valid face (http://www.freecadweb.org/wiki/index.ph ... ing_a_Face) , I am a little confused about this apparent paradox... ?

OS: Linux Mint 15 Olivia
Platform: 64-bit
Version: 0.14.2632 (Git)
Branch: master
Hash: 939bc92acb02662901e9dee4b5ba5d2fddead360
Python version: 2.7.4
Qt version: 4.8.4
Coin version: 3.1.3
SoQt version: 1.5.0
OCC version: 6.5.0
beamer146
Posts: 38
Joined: Sun Nov 24, 2013 12:17 pm

Re: The wires of the faces of eg a box are not closed ?

Postby beamer146 » Mon Jan 13, 2014 10:11 pm

Looking at the edges gives:

Code: Select all

# >>> b.Faces[1].Wires[0].Edges[0].Vertexes[0].Point
# Vector (2.0, 0.0, 4.0)
# >>> b.Faces[1].Wires[0].Edges[0].Vertexes[1].Point
# Vector (2.0, 0.0, 0.0)
# >>> b.Faces[1].Wires[0].Edges[1].Vertexes[0].Point
# Vector (2.0, 3.0, 4.0)
# >>> b.Faces[1].Wires[0].Edges[1].Vertexes[1].Point
# Vector (2.0, 0.0, 4.0)
# >>> b.Faces[1].Wires[0].Edges[2].Vertexes[0].Point
# Vector (2.0, 3.0, 4.0)
# >>> b.Faces[1].Wires[0].Edges[2].Vertexes[1].Point
# Vector (2.0, 3.0, 0.0)
# >>> b.Faces[1].Wires[0].Edges[3].Vertexes[0].Point
# Vector (2.0, 3.0, 0.0)
# >>> b.Faces[1].Wires[0].Edges[3].Vertexes[1].Point
# Vector (2.0, 0.0, 0.0)
Do edges have a direction ? Because they do follow the sides of the face, but it seems they have a direction which always starts from the farthest point from the origin to the nearest point. Maybe that is what is confusing the isClosed test ?
wmayer
Site Admin
Posts: 15756
Joined: Thu Feb 19, 2009 10:32 am

Re: The wires of the faces of eg a box are not closed ?

Postby wmayer » Tue Jan 14, 2014 9:26 am

That's interesting. However, the "closed" attribute is only a flag in the shape C++ class and can be set to true or false from outside. So, the usefulness is a bit questionable.

And of course you can create a face out of the wire:

Code: Select all

f=Part.Face(b.Faces[0].Wires[0])
Part.show(f)
beamer146
Posts: 38
Joined: Sun Nov 24, 2013 12:17 pm

Re: The wires of the faces of eg a box are not closed ?

Postby beamer146 » Tue Jan 14, 2014 11:17 am

And of course you can create a face out of the wire:

Mmm that did not seem to work for me, it leads to invalid objects when extruding, although they initially look fine (cfr viewtopic.php?f=3&t=5364)

Code: Select all

l_faceCopy2 = Part.Face(l_faceCopy.Wires)                  
l_extPath = Base.Vector( l_vctNormal )
l_extPath = l_extPath.multiply( 2.0 )                 
l_mdlCur = l_faceCopy2.extrude( l_extPath )
Although I now see that I used xxx.Wires instead of xxx.Wires[0].
Could that be an issue ?

I will try xxx.Wires[0] later today and report back.
wmayer
Site Admin
Posts: 15756
Joined: Thu Feb 19, 2009 10:32 am

Re: The wires of the faces of eg a box are not closed ?

Postby wmayer » Tue Jan 14, 2014 11:52 am

Could that be an issue ?
Oh yes, this is a problem. The Face constructor supports a single wire or a list of wires. In case of a single wire or a list with only one wire it's clear what happens. If you pass a list of several wires then the first wire is used to create the face and the further wires describe holes in this face.

So, in your example you have something undefined because the other five wires do not lie on the face and thus it's quite obvious that you run into further problems later.
beamer146
Posts: 38
Joined: Sun Nov 24, 2013 12:17 pm

Re: The wires of the faces of eg a box are not closed ?

Postby beamer146 » Tue Jan 14, 2014 1:06 pm

In case of a single wire or a list with only one wire it's clear what happens. If you pass a list of several wires then the first wire is used to create the face and the further wires describe holes in this face.
Maybe not immediately obvious from the code snippit, but l_faceCopy was a (scaled) copy of a single face, so l_faceCopy.Wires is in fact a list with a single wire.
Similar to
>>> b.Faces[1].Wires
[<Wire object at 0x760f8f0>]
from the top post.

So it actually should have worked.

Note: I did not yet try if it works when starting from a simple box. It definetly did not work with the building's roof face I tried it on (as mentioned in viewtopic.php?f=3&t=5364).
beamer146
Posts: 38
Joined: Sun Nov 24, 2013 12:17 pm

Re: The wires of the faces of eg a box are not closed ?

Postby beamer146 » Tue Jan 14, 2014 6:48 pm

Piece of demo code showing the problem even with simple box surfaces below.
The problem seems to be triggered by the scale operation (which is turning out to be full of surprises).
If I remove the scale operation, the wire is still not closed but faceCopy2 is valid.

Code: Select all

from __future__ import division # allows floating point division from integers
# first of all you need the Part nd ( the Drawing module:
import FreeCAD, Part, Drawing, Draft
from FreeCAD import Base

def clearDoc( a_doc ):
	l_aoAllObjs = a_doc.Objects
	for l_objCur in l_aoAllObjs:
		a_doc.removeObject( l_objCur.Name )
m_doc=FreeCAD.activeDocument()
if (m_doc== None):
	m_doc = FreeCAD.newDocument()
clearDoc( m_doc )
l_mdlBox=Part.makeBox(2,3,4)
l_vobBox= m_doc.addObject("Part::Feature", "vobBox")  
l_vobBox.Shape = l_mdlBox
l_faceCur = l_mdlBox.Faces[ 3 ]
FreeCAD.Console.PrintMessage( "Face index 1 : wire 0 closed ? " + str(l_faceCur.Wires[0].isClosed()) + "\n") 
l_vctNormal = l_faceCur.normalAt( 0.5, 0.5 )
l_faceCopy = l_faceCur.copy() 
#l_faceCopy.scale( 2.0, l_faceCopy.CenterOfMass ) Alternative center, but maybe there was something funny going on with centeroffmass
l_faceCopy.scale( 2.0, Base.Vector(2,3,4) )
# Create a new object with the end result of the scaling operation, workaround for the bug that the scaling is not taken into account
# when assigning to a shape
l_faceCopy2 = Part.Face( l_faceCopy.Wires[0] )
FreeCAD.Console.PrintMessage( "faceCopy2 valid ? " + str(l_faceCopy2.isValid()) + "\n") 
l_extPath = Base.Vector( l_vctNormal )
l_mdlTest = l_faceCopy2.extrude( l_extPath )
FreeCAD.Console.PrintMessage( "mdlTest valid ? " + str(l_mdlTest.isValid()) + "\n") 
l_vobTest= m_doc.addObject("Part::Feature", "vobTest"  )
l_vobTest.Shape = l_mdlTest
Output:
Face index 1 : wire 0 closed ? False
faceCopy2 valid ? False
mdlTest valid ? False

Also the check geometry tool indicates problems with the vobTest object

(remark l_faceCopy2 = Part.Face( l_faceCopy.Wires[0] ) or l_faceCopy2 = Part.Face( l_faceCopy.Wires ) gives the same result)