# +++++++++++++++++++++++++++++++++++++++++++++++++
#  A t t e n t i o n :   The calculation might take some minutes!
#
#  This FreeCAD macro creates a new document with 4 sketches and 2 helices as basic geometries
#  1st sketch to create a Revolve
#  2nd sketch to create a Sweep (Ribbon)
#  3rd sketch to create the final Sweep (Tap)
#  4th sketch to create a sweep for comparison
#  Creates a standard helix as path for the Ribbon
#  Creates the Revolve with the 1st sketch
#  Creates the Sweep   with the 2nd sketch
#  Then it builds the section of the objects Revolve and Sweep
#  Upgrades that resulting Section to a Wire object and
#  creates the final sweep with the 3rd sketch and the Wire as path
#
#  The resulting sweep volume is somehow rotating in itself. Ugly!
#  Compare with the sweep below around the standard helix
#  I followed the hint 5 on page http://blogs.solidworks.com/solidworksblog/2012/09/7-simple-tips-for-modeling-springs.html
# +++++++++++++++++++++++++++++++++++++++++++++++++
import FreeCAD, Sketcher, Part, PartGui, Draft
from FreeCAD import Base
from PySide import QtGui

def main():
  global Doc, VecBase, VecRot
  DocName = 'Path0904'
  closeDoc(DocName)
  if App.listDocuments().has_key(DocName):
    print "A document with the name '", DocName, "' already exists.\nPlease specify another document name in the macro."
    return
  App.newDocument(DocName)
  App.setActiveDocument(DocName)
  Doc = App.ActiveDocument
  VecBase = App.Vector(0.00, 0.00, 0.00)
  VecRot  = App.Rotation(-0.707107, 0.00, 0.00, -0.707107)
  create_geometries()

def closeDoc(DocName):
  if App.listDocuments().has_key(DocName):
    App.closeDocument(DocName)
  App.setActiveDocument("")
  App.ActiveDocument=None
  Gui.ActiveDocument=None
  try: Gui.getMainWindow().findChild(QtGui.QTextEdit     , 'Report view'   ).clear()
  except: pass
  try: Gui.getMainWindow().findChild(QtGui.QPlainTextEdit, 'Python console').clear()
  except: pass

def make_TapSketch(Name, Offset):
  Off = float(Offset)
  Skt = Doc.addObject('Sketcher::SketchObject', Name)
  #Skt.Placement = App.Placement(VecBase, VecRot)
  #Skt.Placement = App.Placement(App.Vector(0.00, 0.00, 0.00), VecRot)
  Skt.Placement = App.Placement(App.Vector(0.00, 0.00, Off), VecRot)

  Skt.addGeometry(Part.Line(App.Vector(6.00, 1.00, 0.00), App.Vector(4.00, 0.00, 0.00)))
  Skt.addConstraint(Sketcher.Constraint('DistanceX'    , 0, 2, 4.00))
  Skt.addConstraint(Sketcher.Constraint('DistanceY'    , 0, 2, 0.00))
  Doc.recompute()
  Skt.addGeometry(Part.Line(App.Vector(4.00, 0.00, 0.00), App.Vector(6.00, -1.00, 0.00)))
  Skt.addConstraint(Sketcher.Constraint('Coincident'   , 0, 2, 1, 1))
  Doc.recompute()
  Skt.addGeometry(Part.Line(App.Vector(6.00,-1.00, 0.00), App.Vector(6.00, 1.00, 0.00)))
  Skt.addConstraint(Sketcher.Constraint('Coincident'   , 1, 2, 2, 1))
  Skt.addConstraint(Sketcher.Constraint('Coincident'   , 2, 2, 0, 1))
  Skt.addConstraint(Sketcher.Constraint('DistanceX'    , 1, 2, 6.00))
  Skt.addConstraint(Sketcher.Constraint('DistanceY'    , 1, 2,-1.00))
  Skt.addConstraint(Sketcher.Constraint('DistanceX'    , 0, 1, 6.00))
  Skt.addConstraint(Sketcher.Constraint('DistanceY'    , 0, 1, 1.00))
  Skt.ViewObject.Visibility = False
  Doc.recompute()
  return Skt

def create_sweep(Name, Sect, Spin, **kwargs):
  Frenet = False

  if         kwargs.get('f', None):
    Frenet = kwargs.get('f', None)
  elif       kwargs.get('F', None):
    Frenet = kwargs.get('F', None)

  Swp = Doc.addObject('Part::Sweep', Name)
  #Swp.Sections   = [Sect, ]
  #Swp.Spine      = (Spin, [])
  Swp.Sections   = [Sect]
  Swp.Spine      = (Spin)
  Swp.Solid      = True
  Swp.Frenet     = Frenet
  Swp.ViewObject.Transparency = 50
  Doc.recompute()
  Gui.ActiveDocument.update()
  return Swp

def create_RevolveSketch(Name):
  Skt = Doc.addObject('Sketcher::SketchObject', Name)
  Skt.Placement = App.Placement(VecBase, VecRot)
  Skt.addGeometry(Part.Line(App.Vector(5.00, -0.00, 0.00), App.Vector(5.00, 3.50, 0.00)))
  Skt.addConstraint(Sketcher.Constraint('PointOnObject', 0, 1, -1))
  Skt.addConstraint(Sketcher.Constraint('Vertical'     , 0))
  Doc.recompute()
  Skt.addGeometry(Part.ArcOfCircle(Part.Circle(App.Vector(6.00, 3.50, 0.00), App.Vector(0, 0, 1), 1.00), 2.00, 3.141593))
  Skt.addConstraint(Sketcher.Constraint('Coincident'   , 1, 2, 0, 2))
  Skt.addConstraint(Sketcher.Constraint('Tangent'      , 1, 0))
  Skt.addConstraint(Sketcher.Constraint('Radius'       , 1, 0.50))
  Doc.recompute()
  Skt.addGeometry(Part.Line(App.Vector(5.53, 4.00, 0.00), App.Vector(7.00, 5.00, 0.00)))
  Skt.addConstraint(Sketcher.Constraint('Coincident'   , 2, 1, 1, 1))
  Skt.addConstraint(Sketcher.Constraint('Tangent'      , 1, 2))
  Skt.addConstraint(Sketcher.Constraint('DistanceX'    ,-1, 1, 0, 1, 5.00))
  Skt.addConstraint(Sketcher.Constraint('DistanceX'    , 2, 2, 7.00))
  Skt.addConstraint(Sketcher.Constraint('DistanceY'    , 2, 2, 5.00))
  Skt.addConstraint(Sketcher.Constraint('DistanceY'    ,-1, 1, 1, 3, 3.50))
  Skt.ViewObject.Visibility = False
  Doc.recompute()
  Gui.ActiveDocument.update()
  return Skt

def create_RibbonSketch(Name):
  Skt = Doc.addObject('Sketcher::SketchObject', Name)
  Skt.Placement = App.Placement(VecBase, VecRot)
  Skt.addGeometry(Part.Line(App.Vector(4.00, 0.00, 0.00), App.Vector(8.00, 0.00, 0.00)))
  Skt.addConstraint(Sketcher.Constraint('PointOnObject', 0, 1, -1))
  Skt.addConstraint(Sketcher.Constraint('PointOnObject', 0, 2, -1))
  Skt.addConstraint(Sketcher.Constraint('DistanceX'    ,-1, 1, 0, 1, 4.00))
  Skt.addConstraint(Sketcher.Constraint('DistanceX'    , 0, 4.00))
  Skt.ViewObject.Visibility = False
  Doc.recompute()
  Gui.ActiveDocument.update()
  return Skt

def create_Helix(Name, Off):
  Off = float(Off)
  Hel = Doc.addObject("Part::Helix", Name)
  Hel.Pitch      = 3.00
  Hel.Height     = 6.00
  Hel.Radius     = 5.00
  Hel.Angle      = 0.00
  Hel.LocalCoord = 0
  Hel.Style      = 1
  Hel.Placement  = Base.Placement(App.Vector(0.00, 0.00, Off), Base.Rotation(0.00, 0.00, 0.00, 1.00))
  Hel.ViewObject.Visibility = False
  Doc.recompute()
  Gui.ActiveDocument.update()
  return Hel

def create_Revolve(Name, Src):
  Rev = Doc.addObject("Part::Revolution", "Revolve")
  Rev.Source     = Doc.RevolveSketch
  Rev.Axis       = (0.00, 0.00, 1.00)
  Rev.Base       = (0.00, 0.00, 0.00)
  Rev.Angle      = 360.00
  Rev.Solid      = True
  Rev.ViewObject.Visibility = False
  Doc.recompute()
  Gui.ActiveDocument.update()
  return Rev

def create_section(Name, Base, Tool):
  Sec = Doc.addObject("Part::Section", Name)
  Sec.Base       = Base
  Sec.Tool       = Tool
  Doc.recompute()
  Gui.ActiveDocument.update()
  return Sec

def change_ViewProperties(Obj, **kwargs):
  Color = None
  Size  = None
  Width = None

  if        kwargs.get('c', None):
    Color = kwargs.get('c', None)
  elif      kwargs.get('C', None):
    Color = kwargs.get('C', None)

  if              kwargs.get('s', None):
    Size  = float(kwargs.get('s', None))
  elif            kwargs.get('S', None):
    Size  = float(kwargs.get('S', None))

  if              kwargs.get('w', None):
    Width = float(kwargs.get('w', None))
  elif            kwargs.get('W', None):
    Width = float(kwargs.get('W', None))

  VO = Obj.ViewObject
  VO.Visibility = True

  if Size:
    VO.PointSize  = Size

  if Width:
    VO.LineWidth  = Width

  if Color:
    VO.PointColor = Color
    VO.LineColor  = Color
    VO.ShapeColor = Color

  Doc.recompute()
  Gui.ActiveDocument.update()

def make_wire(Obj):
  Wir = Draft.upgrade([Obj], delete=True)
  Doc.recompute()
  Gui.ActiveDocument.update()
  return Wir

def create_geometries():
  Off = -8.50
  Fren = False
  Skt1 = create_RevolveSketch('RevolveSketch')
  Skt2 = create_RibbonSketch('RibbonSketch')
  Skt3 = make_TapSketch('TapSketch1', 0.00)
  Skt4 = make_TapSketch('TapSketch2', Off)
  Hel1 = create_Helix("RibbonHelix", 0.00)
  Hel2 = create_Helix("StandardHelix", Off)
  Rev1 = create_Revolve('Revolve', Doc.RevolveSketch)
  Rib1 = create_sweep('Ribbon', Doc.RibbonSketch, Doc.RibbonHelix, f=True)
  Sec1 = create_section("Section", Doc.Revolve, Doc.Ribbon)
  Wir1 = make_wire(Doc.Section)
  create_sweep('Tap1', Doc.TapSketch1, Doc.Wire, f=Fren)
  create_sweep('Tap2', Doc.TapSketch2, Doc.StandardHelix, f=Fren)
  change_ViewProperties(Doc.Wire,          c=(1.00,0.00,0.00), s=5.00)
  change_ViewProperties(Doc.StandardHelix, C=(0.00,1.00,0.00), S=5.00)
  Gui.SendMsgToActiveView("ViewFit")
  Gui.ActiveDocument.update()

main()



def ignore():
  Swp2 = Doc.addObject('Part::Sweep', 'Tap1')
  Swp2.Sections   = [Doc.TapSketch1, ]
  Swp2.Spine      = (Doc.Wire, [])
  Swp2.Solid      = True
  Swp2.Frenet     = True
  Doc.recompute()
  Gui.SendMsgToActiveView("ViewFit")
  Doc.recompute()

  Swp3 = Doc.addObject('Part::Sweep', 'Tap2')
  Swp3.Sections   = [Doc.TapSketch2, ]
  Swp3.Spine      = (Doc.StandardHelix, [])
  Swp3.Solid      = True
  Swp3.Frenet     = True
  Doc.recompute()
  Gui.SendMsgToActiveView("ViewFit")
  Doc.recompute()

  WirV1 = Wir1.ViewObject
  WirV1.Visibility = True
  WirV1.PointSize  = 5.00
  WirV1.LineWidth  = 5.00
  Color = (1.00,0.00,0.00)
  WirV1.PointColor = Color
  WirV1.LineColor  = Color
  WirV1.ShapeColor = Color

