Friday, 5 June 2015

FreeCAD: Sheet Metal Update 2

Some screenshots of the current state of the workbench:

My goal sheet metal part and what can be currently done with the workbench:


It took me less than 5 minutes to draw it (I cheated a bit and did not put any real measurements). It sums up the current capabilities.

The object in the tree view:


You can also see the two orange icons, the only ones by now: "base fold" and "fold on edge".

The properties of the main feature, the fold:


It seems not too different from Update 1, but there has been a lot of work under the hood. Topological naming is a headache (every time a shape is modified, freecad sorts its edges, faces and vertexes randomly), and for the unfold, currently I have two approaches, the one that is currently working, produces this:


The other method, when finished, will allow to unfold partially and set different bend radius and k factors for each fold.

Thought priority is to finish Fold part class and unfold methods, to take a rest from it I code other tools, for example, hem along edges:


Or tear drop fold (a simplified fold object):


Slowly, this is starting to feel mature enough to use it in for real world. Once I solve some key problems, I will launch the crowdfunding campaing.

Any comment is greatly appreciated!

Thursday, 14 May 2015

FreeCAD: Sheet Metal Update 1

After some time without touching FreeCAD, I have managed to go a bit further at the development of the sheet metal workbench. Although is not really a "workbench", but a set of scripts at the moment, most of the critical part is done: workflow, document structure, data tree...

A screenshot:



This video sums up the current possibilities:


Objects are totally parametric and unfold algorithm is easier then ever. Next things to do are folds created from sketches (almost completed), get the unfold algorithm to work correctly with the k factor and other bend methods, set up the workbench with icons, and a lot of small utilities like reliefs, slots, punching...


The idea for this workbench is to be open source, but in a special way, because once completed and tested, I will start some kind of "crowdfunding" campaign so I can get some economic feedback. Once a specified amount is reached, I will upload the complete code to GitHub and start to work at documentation and further integration with FreeCAD (if it is considered good enough by the main devs).

With this method I hope to prove that open source software and economic benefit are not antagonist concepts.

What do you think?

EDITED: The development of this workbench (including funding campaign) is stopped until the first release of the project NiCr.

Monday, 20 April 2015

FreeCAD: Sticker Sketch and Text

Sometimes you need to model a special part like a shift drum for a motorcycle gearbox or something more simple like putting text on your perfectly modelled cup of coffee. While the content of this post does not completely solve any of this problems, it shows an important step forward. I'm doing this because of its similarity with some parts of the sheet metal workbench core.

What it does is to roll around a cylindrical surface a sketch or a text string. Code at the end of the post.

Sketch sticker:

This is a plain sketch tangent to a cylinder, with a random polygon inside:

 

The script rolls the sketch along the cylinder surface. Only straight lines at the moment.

 

Text sticker:

Equal to the previous one but with strings. The font must must be made only of straight lines.



It works for any face orientation (but not character length, this will be improved )


Text Sticker Code:


"""
Javier Martinez Garcia  2015  GPL
"Text sticker" script
"""

import Draft
from math import sin, cos, pi

BaseCylinder = Gui.Selection.getSelectionEx()[0].SubObjects[0]

# Cylinder axis:
for edge in BaseCylinder.Edges:
  if str(edge.Curve)[0] == "C":
    AxisPoint = edge.Curve.Center
    AxisDirection = edge.Curve.Axis
    CylinderRadius = edge.Curve.Radius
    break

# For text string:
FaceList = []
SelStrings = Gui.Selection.getSelection()[1].Shape.Wires
wire0 = SelStrings[0]
p1 = wire0.Edges[0].Curve.StartPoint
p2 = wire0.Edges[0].Curve.EndPoint
p3 = wire0.Edges[1].Curve.EndPoint
va = p1 - p2
vb = p3 - p2
SketchNormal = ( va.cross( vb ) ).normalize()
TangencyPoint = AxisPoint + SketchNormal*CylinderRadius
CylRevPlane = ( SketchNormal.cross( AxisDirection ) ).normalize() # perpendicular

for wire in SelStrings:
  def H( n, m ):
    #Hamilton product
    w = n[0]*m[0] - n[1]*m[1] - n[2]*m[2] - n[3]*m[3]
    i = n[0]*m[1] + n[1]*m[0] + n[2]*m[3] - n[3]*m[2]
    j = n[0]*m[2] - n[1]*m[3] + n[2]*m[0] + n[3]*m[1]
    k = n[0]*m[3] + n[1]*m[2] - n[2]*m[1] + n[3]*m[0]
    return ( w, i, j, k )

  def RotateVector( V, Axis, alpha ):
    #Rotate 3d vector with axis and angle using quaternions
    csa2 = cos( alpha / 2.0 )
    ssa2 = sin( alpha / 2.0 )
    R = ( csa2, ssa2*Axis[0], ssa2*Axis[1], ssa2*Axis[2] )
    RT = ( csa2, -ssa2*Axis[0], -ssa2*Axis[1], -ssa2*Axis[2] )
    V = ( 0, V[0], V[1], V[2] )
    RV = H( H( R, V ), RT )
    return ( RV[1], RV[2], RV[3] )

  #projectpointocylinder
  def point2Cyl(p):
    # input p = FreeCAD.Vector( x, y, z )
    L0 = FreeCAD.Vector(p)
    L1 = FreeCAD.Vector(p)
    E_TGL_P0A = L0.projectToPlane( TangencyPoint, CylRevPlane )
    E_TGL_P0B = L1.projectToPlane( TangencyPoint, CylRevPlane ).projectToPlane( AxisPoint, SketchNormal )
    VBA = E_TGL_P0A - E_TGL_P0B 
    VBA_N = (E_TGL_P0A - E_TGL_P0B  ).normalize()
    ARC_RAD = ( p - E_TGL_P0A ).Length / CylinderRadius
    # Turn direction
    Aux_VRotA = FreeCAD.Vector( RotateVector( VBA_N, AxisDirection, ARC_RAD ) )
    Aux_VRotB = FreeCAD.Vector( RotateVector( VBA_N, AxisDirection*-1, ARC_RAD ) )
    if (Aux_VRotA - p ).Length > ( Aux_VRotB - p ).Length:
      VRot =  Aux_VRotB

    else:
      VRot = Aux_VRotA

    RP0 = FreeCAD.Vector(VRot).multiply( CylinderRadius ) + E_TGL_P0B
    return RP0
  
  
  WireBS = []
  for edge in wire.Edges:
    points = []
    for i in range(100):
      p = edge.valueAt( edge.Length*i / 100.0 )
      rp = point2Cyl(p)
      points.append( rp )

    rp = point2Cyl( edge.Curve.EndPoint )
    points.append( rp )

    SPL = Part.BSplineCurve()
    SPL.interpolate( points )
    SPL = SPL.toShape()
    WireBS.append( SPL )
  
  Face = Part.makeFilledFace( WireBS )
  FaceList.append( Face )


Compound = Part.Compound( FaceList )
Part.show( Compound )


To use it,  create a cylinder, place a string tangent to it; select the cylindrical surface and the text; run the script. Is very important that the font type of the text is made from straight lines, otherwise it will fail. The font I've used for testing is "UASquare".

Next step is to get it to work with circular edges.

UPDATE 1


The script for sketches is almost working, some screenshots:


Top view of the generated frame:


Generated frame:



This is the step that I'm trying to automatize:


Create faces from edges, create shell from faces, create solid from shell.


Bye!!