Browsed by
Tag: math

Equation Sketcher

Equation Sketcher

Compatible with WizoScript 3.00 and later.

Enter a formula and a Bspline is added to your chosen sketch with the mathematical shape. X and Y can be swapped if needed. The number of points for calculation is controllable. The start of the line is offset to begin at a node manually placed on the sketch before running the script.

from __future__ import division
from math import sqrt

Win = Windows()

ScriptName = "Equation Sketch"

Options = []
Options.append([None, WindowsInputTypes.Label, "The sketch must have a node added already that marks the start of the line"])
Options.append(["Equation y = ", WindowsInputTypes.String, "0.1*x**2"])
Options.append(["Sketch", WindowsInputTypes.Sketch, None])
Options.append(["Start X (at node)", WindowsInputTypes.Real, 0])
Options.append(["End X", WindowsInputTypes.Real, 10])
Options.append(["Number of points", WindowsInputTypes.Integer, 10])
Options.append(["Swap X and Y", WindowsInputTypes.Boolean, False])

Values = Win.OptionsDialog(ScriptName, Options)
if Values == None:
  sys.exit()

# get the inputs
Equation = Values[0]
Sk = Values[1]
StartX = Values[2]
EndX = Values[3]
NumPoints = Values[4]
SwapXY = Values[5]

# validate
if not Equation:
  Win.ErrorDialog("No equation entered", ScriptName)
  sys.exit()
if Sk == None:
  Win.ErrorDialog("No sketch selected", ScriptName)
  sys.exit()
if StartX > EndX:
  Win.ErrorDialog("Start X value is greater than end X value", ScriptName)
  sys.exit()
if NumPoints < 2:
  Win.ErrorDialog("Invalid number of points", ScriptName)
  sys.exit()

# get the part that defines the sketch
Prt = Sk.GetPart()

# check sketch defines a node
# we assume first sketch figure is the node
if len(Sk.Figures) == 0:
  Win.ErrorDialog("The sketch doesn't have a node defined", ScriptName)
  sys.exit()
if isinstance(Sk.Figures[0], SketchPoint) == False:
  Win.ErrorDialog("Can't find node on sketch", ScriptName)
  sys.exit()

# get location of node
NodeX = Sk.Figures[0].X
NodeY = Sk.Figures[0].Y

# we only import this now because it can cause a bit of a delay
from sympy import *

# parse equation
x = Symbol("x")
Eq = sympify(Equation)

# work out how much we increase x between points
StepX = (EndX - StartX) / NumPoints

# calculate the points
Points = []
ValX = StartX
for p in xrange(NumPoints):
  ValY = Eq.subs(x, ValX)
  if SwapXY == True:
    PY = ValX
    PX = ValY
  else:
    PX = ValX
    PY = ValY
  Points.extend([float(PX + NodeX), float(PY + NodeY)])
  ValX = ValX + StepX

# generate the bspline
Sk.AddBsplineThroughPoints(3, Points, False)
Cylinder Between Two Points II

Cylinder Between Two Points II

Compatible with WizoScript 3.00 and later.

Inserts a cylinder between two points.

from math import sqrt

Win = Windows()

Options = []
Options.append(["Start Point", WindowsInputTypes.Point, None])
Options.append(["End Point", WindowsInputTypes.Point, None])
Options.append(["Diameter", WindowsInputTypes.Real, 5])

Values = Win.OptionsDialog("Cylinder", Options)
if Values == None:
  sys.exit()
if Values[0] == None:
  Win.ErrorDialog("No start point selected", "Cylinder")
  sys.exit()
if Values[1] == None:
  Win.ErrorDialog("No end point selected", "Cylinder")
  sys.exit()
if Values[2] <= 0:
  Win.ErrorDialog("Invalid diameter", "Cylinder")
  sys.exit()

# get the part that defines the first point
# it is possible the second point is on a different part but we will assume
# they are on the same part
P = Values[0].GetPart()

# get points and diameter
cyl_p1 = Values[0].GetCoordinates()
cyl_p2 = Values[1].GetCoordinates()
diameter = Values[2]

# get length of cynlinder using euclidean distance
length = sqrt((cyl_p2[0] - cyl_p1[0])**2 + (cyl_p2[1] - cyl_p1[1])**2 + (cyl_p2[2] - cyl_p1[2])**2)
 
# calculate normal vector for the plane at the first end of the cylinder
normal_vector = [cyl_p2[0] - cyl_p1[0], cyl_p2[1] - cyl_p1[1], cyl_p2[2] - cyl_p1[2]]
 
# create plane for one end of the cylinder
cyl_plane = P.AddPlane("Cyl Start Plane", normal_vector, cyl_p1)
 
P.AddAxis("Cylinder Axis", cyl_p1, cyl_p2)
 
# draw a circle on the plane
S = P.AddSketch("Cylinder End", cyl_plane)
[cx, cy] = S.GlobaltoPoint(cyl_p1[0], cyl_p1[1], cyl_p1[2])
S.AddCircle(cx, cy, diameter, False)
 
# extrude into a cylinder
P.AddExtrudeBoss("Cylinder", S, length, True)
Triangle

Triangle

Compatible with WizoScript versions: 2.51

Simple sketch of a triangle with angles 90, 15, 75 degrees.

# Create triangle with angles 90, 15, 75
 
import math
 
# set up parameters
Theta = 15.0
Adjacent = 100.0
 
# calculate side
Opposite = Adjacent * math.tan(math.radians(15.0))
 
# generate three vertices of triangle
P1_X = 0
P1_Y = 0
 
P2_X = Adjacent
P2_Y = 0
 
P3_X = Adjacent
P3_Y = Opposite
 
# create part and sketch
P = Part("Foo")
S = P.AddSketch("Shape", P.GetPlane("XY-Plane"))
 
# draw it
S.AddLine(P1_X, P1_Y, P2_X, P2_Y, False)
S.AddLine(P2_X, P2_Y, P3_X, P3_Y, False)
S.AddLine(P3_X, P3_Y, P1_X, P1_Y, False)
Cooke Triplet Lens System

Cooke Triplet Lens System

Compatible with WizoScript versions: 1.70

Generates a Cooke Triplet lens system that matches the description in US patent 2,503,751 A. Can be used as a general-purpose lens generator of any type. Shows how to calculate the lensmaker’s equation and find missing values.

# Generates a Cooke Triplet lens system that matches the description
# in US patent 2,503,751 A, W Litten, et al
# EF = 100mm, f/1.9
 
import sympy
from sympy import *
import math
 
Units.Current = UnitTypes.Millimeters
 
# location to store part files
OutputFolder = "P:\\temp"
 
# calculates the back radius of a lens based on the other parameters
# uses the lensmaker's equation
def GetBackRadius(FrontRadius, Thickness, RefractiveIndex, FocalLength):
  rb = Symbol('rb')
  Equation = Eq((RefractiveIndex-1)*((1/FrontRadius)-(1/rb)+(((RefractiveIndex-1)*Thickness)/(RefractiveIndex*FrontRadius*rb))),(1/FocalLength))
  # we don't bother rearranging the equation, instead we let the sympy module do that for us
  BackRadius = solve(Equation)[0]
  return BackRadius
 
# creates a part representing a lens based on a set of parameters
def GenerateLens(Name, Folder, FrontRadius, Thickness, RefractiveIndex, FocalLength, Diameter):
  # get missing parameter
  BackRadius = GetBackRadius(FrontRadius, Thickness, RefractiveIndex, FocalLength)
 
  # check diameter is small enough
  if Diameter > abs(FrontRadius):
    print "%s diameter is larger than the front radius %f" % (Name, FrontRadius)
    return
  if Diameter > abs(BackRadius):
    print "%s diameter is larger than the back radius %f" % (Name, BackRadius)
    return
 
  # create new part
  Lens = Part(Name)
 
  # start creating the 2d sketch representing the shape of the lens
  Profile = Lens.AddSketch("Profile", Lens.GetPlane("XY-Plane"))
 
  LensRadius = Diameter / 2.0
 
  # draw shape of the front of the lens, it can be flat, convex or concave
  if FrontRadius == oo:
    FEndX = 0
    Profile.AddLine(0, 0, FEndX, LensRadius, False)
  elif FrontRadius > 0:
    Angle = asin(LensRadius / FrontRadius) 
    FEndX = FrontRadius - (cos(Angle) * FrontRadius)
    Profile.AddArcCenterStartEnd(FrontRadius, 0, FEndX, LensRadius, 0, 0, False)
  else:
    FrontRadius = -FrontRadius
    Angle = asin(LensRadius / FrontRadius)
    FEndX = (cos(Angle) * FrontRadius) - FrontRadius
    Profile.AddArcCenterStartEnd(-FrontRadius, 0, 0, 0, FEndX, LensRadius, False)
 
  # draw shape of the back of the lens, it can be flat, convex or concave
  if BackRadius == oo:
    BEndX = Thickness
    Profile.AddLine(Thickness, 0, BEndX, LensRadius, False)
  elif BackRadius < 0:
    BackRadius = -BackRadius
    Angle = asin(LensRadius / BackRadius)
    BEndX = (cos(Angle) * BackRadius) - BackRadius + Thickness
    Profile.AddArcCenterStartEnd(Thickness - BackRadius, 0, Thickness, 0, BEndX, LensRadius, False)
  else:
    Angle = asin(LensRadius / BackRadius)
    BEndX = -(cos(Angle) * BackRadius) + BackRadius + Thickness
    Profile.AddArcCenterStartEnd(Thickness + BackRadius, 0, BEndX, LensRadius, Thickness, 0, False)
     
  # check diameter of lens again
  if FEndX > BEndX:
    print "%s diameter is too large" % Name
    return
 
  # if this is not a "thin" lens then draw top of profile
  if FEndX != BEndX:
    Profile.AddLine(FEndX, LensRadius, BEndX, LensRadius, False)
 
  # draw line of profile along x axis (optical axis)
  Profile.AddLine(0, 0, Thickness, 0, False)
 
  # create lens by revolving sketch around x axis
  Lens.AddRevolveBoss("Lens", Profile, Lens.GetAxis("X-Axis"), 360.0)
   
  # add reference planes to aid in aligning this lens with others
  Lens.AddPlane("Front", Lens.GetPlane("YZ-Plane"), 0);
  Lens.AddPlane("Back", Lens.GetPlane("YZ-Plane"), Thickness);
   
  # save and close
  Lens.Save(Folder)
  Lens.Close()
 
# lens 1
GenerateLens("Lens1", OutputFolder, 62.63, 25.56, 1.745, 73.2, 40.0)
# lens 2
GenerateLens("Lens2", OutputFolder, -66.47, 4.51, 1.647, -37.74, 36.0)
# lens 3
GenerateLens("Lens3", OutputFolder, 119.5, 19.92, 1.697, 54.88, 30.0)
Parameterized Mobius Strip

Parameterized Mobius Strip

Compatible with WizoScript versions: 1.70

Demonstrates generation of a mobius strip based on a set of parameters. Uses 2D sketch copying and rotation followed by a loft. Requires Geomagic Design 16.0.1.16490 or later.

# creates a mobius strip with a configurable number of rotations
 
Mobius = Part("Mobius")
 
# dimensions of mobius strip
Diameter = 100.0
Width = 20.0
Height = 5.0
# number of 360 degree twists in mobius strip
Rotations = 2
# more steps = better accuracy
Steps = 30
 
# calculate how far we rotate through 360 degrees for each step
RotationPerStep = Rotations / float(Steps) * 360.0
DegreesPerStep = 360.0 / Steps
 
# create the base sketch we will use as a template for all other sketches
S0Plane = Mobius.GetPlane("XY-Plane")
S0 = Mobius.AddSketch("S0", S0Plane)
S0.AddRectangle(Diameter, -Height / 2, Diameter + Width, Height / 2, False)
Sketches = [S0]
 
# generate sketches
for Step in range (1, Steps):
  Plane = Mobius.AddPlane("S" + str(Step), S0Plane, Mobius.GetAxis("Y-Axis"), DegreesPerStep * Step)
  Sketch = Mobius.AddSketch("S" + str(Step), Plane)
  Sketch.CopyFrom(S0, RotationPerStep * Step, Diameter + (Width / 2), 0, 0, 0, 0, 0, 100.0)
  Sketches.append(Sketch)
 
# create loft, connecting ends
Mobius.AddLoftBoss("Strip", Sketches, True, True, False, True)
Cylinder to a Specific Point

Cylinder to a Specific Point

Compatible with WizoScript versions: 1.50

Creates a cylinder that stretches from the origin to a user-defined point. It does this by calculating the plane to start the cylinder from. Demonstrates calculating the equation of a plane then create the plane in Geomagic Design.

# create a cylinder from the origin to an arbitrary point
 
from math import sqrt
 
# ends of cylinder are centered on these points
# first point must be the origin
cyl_p1 = [0, 0, 0]
cyl_p2 = [10, 14, 8]
 
# diameter of cylinder
diameter = 6
 
# get length of cynlinder using euclidean distance
length = sqrt((cyl_p2[0] - cyl_p1[0])**2 + (cyl_p2[1] - cyl_p1[1])**2 + (cyl_p2[2] - cyl_p1[2])**2)
 
# calculate normal vector for the plane at the first end of the cylinder
normal_vector = [cyl_p2[0] - cyl_p1[0], cyl_p2[1] - cyl_p1[1], cyl_p2[2] - cyl_p1[2]]
 
# get equation of plane
# Ax + By + Cz = D
A = normal_vector[0]
B = normal_vector[1]
C = normal_vector[2]
D = -((A * cyl_p1[0]) + (B * cyl_p1[1]) + (C * cyl_p1[2]))
 
# calculate a point on the plane
plane_p2 = [cyl_p1[0] - 1, cyl_p1[1] - 2, 0]
plane_p2[2] = (0 - D - (A * plane_p2[0]) - (B * plane_p2[1])) / float(C)
 
# calculate another point on the plane
plane_p3 = [cyl_p1[0] - 2, cyl_p1[1] - 2, 0]
plane_p3[2] = (0 - D - (A * plane_p3[0]) - (B * plane_p3[1])) / float(C)
 
# create part
P = Part("Cylinder Test")
 
# create plane using origin and two points on plane
cyl_plane = P.AddPlane("Cyl Plane", cyl_p1, plane_p2, plane_p3)
 
# create circle on plane
sketch = P.AddSketch("Cyl End", cyl_plane)
sketch.AddCircle(cyl_p1[0], cyl_p1[1], diameter, False)
 
# extrude to cylinder
P.AddExtrudeBoss("Cynlinder", sketch, length, True)
Calculating Length of Curves

Calculating Length of Curves

Compatible with WizoScript versions: 1.50

Calculates the length of y = 2x^2 over the range x = 5mm to x = 10mm using calculus.

import sympy
from sympy import *
 
x = Symbol('x')
 
formula = 2 * x**2
x_minimum = 5.0
x_maximum = 10.0
 
d = diff(formula, x)
i = integrate(sqrt(1 + d**2), (x, x_minimum, x_maximum))
length = i.evalf()
print "Length of curve over x=%.3f to x=%.3f is %.3f mm" % (x_minimum, x_maximum, length)
Calculating Length of Polylines

Calculating Length of Polylines

Compatible with WizoScript versions: 1.42

This example adds up the total lengths of all lines in a sketch in a part that is already open.

# Calculates the total length of all lines in a sketch
# This script assumes a part called 'Polyline' is already open
# and contains a single sketch called 'Sketch<1>' which has the lines
# to measure
 
Units.Current = UnitTypes.Millimeters
 
# get already opened part and then get sketch on part
P = Part("Polyline", False)
S = P.GetSketch("Sketch<1>")
 
# get total length of all lines in the sketch
TotalLength = 0
for Figure in S.Figures:
  if Figure.IsReference == False:
    TotalLength = TotalLength + Figure.Length
 
print "Total length of polyline = %.3f mm" % TotalLength
Geodesic Dome Reference Geometry

Geodesic Dome Reference Geometry

Compatible with WizoScript versions: 1.42

Tessellates a sphere into triangles and generates a reference point at each vertex. Demonstrates how complex reference geometry can be created.

To increase the number of triangles increase the detail value, however use with caution as a small increase can result in a very large number of triangles which will take a long time to generate.

# tessellates a sphere into triangles and generates a reference point at each vertex
# adapted from
# http://musingsofninjarat.wordpress.com/spheres-through-triangle-tessellation/
 
from math import *
 
A = 0.525731112119133606
B = 0.850650808352039932
 
icosa_indices = [0 for x in xrange(20)]
icosa_indices[0]  = [0,4,1]
icosa_indices[1]  = [0,9,4]
icosa_indices[2]  = [9,5,4]
icosa_indices[3]  = [4,5,8]
icosa_indices[4]  = [4,8,1]
icosa_indices[5]  = [8,10,1]
icosa_indices[6]  = [8,3,10]
icosa_indices[7]  = [5,3,8]
icosa_indices[8]  = [5,2,3]
icosa_indices[9]  = [2,7,3]
icosa_indices[10] = [7,10,3]
icosa_indices[11] = [7,6,10]
icosa_indices[12] = [7,11,6]
icosa_indices[13] = [11,0,6]
icosa_indices[14] = [0,1,6]
icosa_indices[15] = [6,1,10]
icosa_indices[16] = [9,0,11]
icosa_indices[17] = [9,11,2]
icosa_indices[18] = [9,2,5]
icosa_indices[19] = [7,2,11]
 
icosa_verts = [0 for x in xrange(12)]
icosa_verts[0]  = [A,0.0,-B]
icosa_verts[1]  = [-A,0.0,-B]
icosa_verts[2]  = [A,0.0,B]
icosa_verts[3]  = [-A,0.0,B]
icosa_verts[4]  = [0.0,-B,-A]
icosa_verts[5]  = [0.0,-B,A]
icosa_verts[6]  = [0.0,B,-A]
icosa_verts[7]  = [0.0,B,A]
icosa_verts[8]  = [-B,-A,0.0]
icosa_verts[9]  = [B,-A,0.0]
icosa_verts[10] = [-B,A,0.0]
icosa_verts[11] = [B,A,0.0]
 
def normalize_vert(a):
  d = sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2])
  a[0] = a[0] / d
  a[1] = a[1] / d
  a[2] = a[2] / d
  return a
   
def draw_recursive_tri(a, b, c, div, r, vertices):
  if div == 0:
    v1 = (a[0]*r, a[1]*r, a[2]*r)
    v2 = (b[0]*r, b[1]*r, b[2]*r)
    v3 = (c[0]*r, c[1]*r, c[2]*r)
    vertices.add(v1)
    vertices.add(v2)
    vertices.add(v3)
  else:
    ab = [0, 0, 0]
    ac = [0, 0, 0]
    bc = [0, 0, 0]
 
    for i in range(0, 3):
      ab[i] = (a[i] + b[i]) / 2.0
      ac[i] = (a[i] + c[i]) / 2.0
      bc[i] = (b[i] + c[i]) / 2.0
     
    ab = normalize_vert(ab)
    ac = normalize_vert(ac)
    bc = normalize_vert(bc)
     
    draw_recursive_tri(a, ab, ac, div - 1, r, vertices)
    draw_recursive_tri(b, bc, ab, div - 1, r, vertices)
    draw_recursive_tri(c, ac, bc, div - 1, r, vertices)
    draw_recursive_tri(ab, bc, ac, div - 1, r, vertices)
 
# calculates the triangle vertices for a given sphere and level of detail
def calculate_sphere(detail, radius):
  # we use a set because each vertex must be unique and sets can only contain unique values
  vertices = set()
  for i in range(0, 20):
    draw_recursive_tri(icosa_verts[icosa_indices[i][0]], icosa_verts[icosa_indices[i][1]], icosa_verts[icosa_indices[i][2]], detail, radius, vertices);
  return vertices
 
# use a low level of detail - increasing this value drastically increases the number of triangles
Detail = 1
# radius of sphere in millimeters
Radius = 10
 
# generate a set of triangle vertices
Vertices = calculate_sphere(Detail, Radius)
 
# create a new part
MyPart = Part("Geodesic Sphere")
# add the reference points to the part
Number = 0
for Vertex in Vertices:
  MyPart.AddPoint("Geodesic " + str(Number), Vertex[0], Vertex[1], Vertex[2])
  Number = Number + 1
Parabolic Curve

Parabolic Curve

Compatible with WizoScript versions: 1.42

Creates a parabolic curve from 0cm, 0cm to 15cm, 60cm.

# Draws a parabolic curve in a sketch from 0cm,0cm to 15cm,60cm
 
Units.Current = UnitTypes.Centimeters
 
# y = ax^2 where x = 15 and y = 60
def para(x):
  y = 0.2666666666 * x**2
  return y
 
MyPart = Part("My Part")
Parabola = MyPart.AddSketch("Parabola", MyPart.GetPlane("XY-Plane"))
 
# generate list of points
points = []
for x in range(0, 16):
  points.extend([x, para(x)])
 
Parabola.AddBsplineThroughPoints(3, points, False)