#! python
# (c) 2011 Werner Mayer LGPL
#

from __future__ import division  # allows floating point division from integers
import FreeCAD, Part, math
from FreeCAD import Base


class Epitrochoid:
    def __init__(self, obj):
        """Add the properties: Radius1, Radius2, Distance, Segments"""
        obj.addProperty(
            "App::PropertyLength", "Radius1", "Epitrochoid", "Interior radius", locked=True
        ).Radius1 = 60.0
        obj.addProperty(
            "App::PropertyLength", "Radius2", "Epitrochoid", "Exterior radius", locked=True
        ).Radius2 = 20.0
        obj.addProperty(
            "App::PropertyLength", "Distance", "Epitrochoid", "Distance", locked=True
        ).Distance = 10.0
        obj.addProperty(
            "App::PropertyInteger",
            "Segments",
            "Epitrochoid",
            "Number of the line segments",
            locked=True,
        ).Segments = 72
        obj.Proxy = self

    def onChanged(self, fp, prop):
        if (
            prop == "Radius1" or prop == "Radius2" or prop == "Distance" or prop == "Segments"
        ):  # if one of these is changed
            self.execute(fp)

    def execute(self, fp):  # main part of script
        steps = fp.Segments  # get value from property
        dang = math.radians(360 / steps)
        r2 = fp.Radius2
        r1 = fp.Radius1
        f1 = r1 + r2
        f2 = f1 / r2
        d = fp.Distance
        ang = 0
        z = 0

        if r2 == 0:
            raise ValueError("Exterior radius must not be zero")

        for i in range(steps):
            if i == 0:
                x1 = f1 * math.cos(ang) - d * math.cos(f2 * ang)  # coords for line startpoint
                y1 = f1 * math.sin(ang) - d * math.sin(f2 * ang)
                ang = dang
                x2 = f1 * math.cos(ang) - d * math.cos(f2 * ang)  # coords for line endpoint
                y2 = f1 * math.sin(ang) - d * math.sin(f2 * ang)
                seg = Part.makeLine((x1, y1, z), (x2, y2, z))
                wire = Part.Wire([seg])
                x1 = x2
                y1 = y2
            else:
                x2 = f1 * math.cos(ang) - d * math.cos(f2 * ang)
                y2 = f1 * math.sin(ang) - d * math.sin(f2 * ang)
                seg = Part.makeLine((x1, y1, z), (x2, y2, z))
                wire = Part.Wire([wire, seg])
                x1 = x2
                y1 = y2
            ang = ang + dang  # increment angle
        fp.Shape = wire  # result shape


def makeEpitrochoid():
    doc = FreeCAD.activeDocument()
    if doc is None:
        doc = FreeCAD.newDocument()
    epitrochoid = doc.addObject("Part::FeaturePython", "Epitrochoid")  # add object to document
    epitrochoid.Label = "Epitrochoid"
    Epitrochoid(epitrochoid)
    epitrochoid.ViewObject.Proxy = 0
    doc.recompute()


if __name__ == "__main__":  # feature will be generated after macro execution
    makeEpitrochoid()
