Advertisement
Guest User

Untitled

a guest
Oct 20th, 2019
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.70 KB | None | 0 0
  1. # stl-surface.py
  2.  
  3. # Generate a 3D model based on a 2D equation
  4.  
  5. # The model will be rectangular with a flat base. The top surface is based on
  6. # a provided equation in "surface_function". The file name can be set with the
  7. # output_filename variable. The x and y width of the model and the grid spacing
  8. # is defined by the following parameters.
  9.  
  10. # x_spacing
  11. # y_spacing
  12. # x_number_of_points
  13. # y_number_of_points
  14.  
  15. # There may be a warning that model isn't closed. Most likely this is an error
  16. # caused by the way numpy-stl tests the model. This usually only happens on
  17. # models with a large number of faces. Ignore this warning but check the model
  18. # to be sure.
  19.  
  20. import numpy as np
  21. from stl import mesh
  22. import math
  23. from typing import NamedTuple, List
  24.  
  25.  
  26. # Simple coordinate storage class
  27. class Vertex(NamedTuple):
  28. x: float
  29. y: float
  30. z: float
  31.  
  32.  
  33. # The function that describes the upper surface
  34. def surface_function(x, y):
  35. return 10 - 2*(1 - math.cos(2 * x * math.pi / 20)) *\
  36. (1 - math.cos(2 * y * math.pi / 20))
  37.  
  38.  
  39. # Define dimensions and display parameters
  40. output_filename = "model.stl"
  41. x_spacing = 1
  42. x_number_of_points = 101
  43.  
  44. y_spacing = 1
  45. y_number_of_points = 101
  46.  
  47. print("x size = " + str(x_spacing * (x_number_of_points - 1)))
  48. print("y size = " + str(y_spacing * (y_number_of_points - 1)))
  49.  
  50. number_of_top_coordinates = x_number_of_points * y_number_of_points
  51. number_of_top_faces = (x_number_of_points - 1) * \
  52. (y_number_of_points - 1) * 2
  53. print("number of coordinates in the upper surface = " +
  54. str(number_of_top_coordinates))
  55. print("number of faces in the upper surface = " + str(number_of_top_faces))
  56.  
  57. total_number_of_faces = number_of_top_faces * 2 +\
  58. 4 * (y_number_of_points + x_number_of_points - 2)
  59. print("total number of faces in the model = " + str(total_number_of_faces))
  60.  
  61. # Storage for vertex coordinates using the x and y index of the coordinates
  62. top_vertices = dict()
  63. bottom_vertices = dict()
  64.  
  65. # Create the vertices for the top and bottom surfaces
  66. for y_index in range(y_number_of_points):
  67. for x_index in range(x_number_of_points):
  68. x_coord = x_index * x_spacing
  69. y_coord = y_index * y_spacing
  70.  
  71. # Create the vertices for the top surface. These are defined by
  72. # surface_function
  73. top_vertices[(x_index, y_index)] =\
  74. Vertex(x_coord, y_coord, surface_function(x_coord, y_coord))
  75.  
  76. # Create the vertices for the bottom flat surface at z = 0
  77. bottom_vertices[(x_index, y_index)] =\
  78. Vertex(x_coord, y_coord, 0)
  79.  
  80. # Preallocate storage for the triangles that make up the upper and lower faces.
  81. # I've chosen to preallocate storage for the face data instead of constantly
  82. # growing the list. It shouldn't make a difference for models with a small
  83. # number of faces, but it seems to improve speed for larger models.
  84. top_faces: List[tuple or None] = [None] * \
  85. ((x_number_of_points - 1) *
  86. (y_number_of_points - 1) * 2)
  87. bottom_faces: List[tuple or None] = [None] * \
  88. ((x_number_of_points - 1) *
  89. (y_number_of_points - 1) * 2)
  90.  
  91. # Every vertex in the grid (apart from ones on the top and right sides)\
  92. # correspond to 2 triangular faces. For example, in a grid with spacing of 1,
  93. # the coordinate of (x, y) would correspond to two triangles. The order of the
  94. # coordinates in each face is important as it defines the outward facing
  95. # direction of the face based on the right hand rule.
  96.  
  97. # (x, y), (x + 1, y), (x + 1, y + 1)
  98. # (x, y), (x + 1, y + 1), (x, y + 1)
  99.  
  100. # *---*---*
  101. # | / | / |
  102. # *---*---
  103. # | / | / |
  104. # *---*---*
  105.  
  106. counter = 0
  107. for y_index in range(y_number_of_points - 1):
  108. for x_index in range(x_number_of_points - 1):
  109.  
  110. # Add faces for the top surface by adding the coordinates of three
  111. # vertices to a tuple
  112. top_faces[counter * 2] = ((top_vertices[x_index, y_index],
  113. top_vertices[x_index + 1, y_index + 1],
  114. top_vertices[x_index, y_index + 1]))
  115. top_faces[counter * 2 + 1] = ((top_vertices[x_index, y_index],
  116. top_vertices[x_index + 1, y_index],
  117. top_vertices[x_index + 1, y_index + 1]))
  118.  
  119. # Add faces for the bottom surface
  120. bottom_faces[counter * 2] =\
  121. ((bottom_vertices[x_index, y_index],
  122. bottom_vertices[x_index, y_index + 1],
  123. bottom_vertices[x_index + 1, y_index + 1]))
  124. bottom_faces[counter * 2 + 1] =\
  125. ((bottom_vertices[x_index, y_index],
  126. bottom_vertices[x_index + 1, y_index + 1],
  127. bottom_vertices[x_index + 1, y_index]))
  128.  
  129. counter += 1
  130.  
  131. # Add faces along the edge of the model to close it. These faces are parallel
  132. # to the x-axis
  133. x_faces_1: List[tuple or None] = [None] * ((x_number_of_points - 1) * 2)
  134. x_faces_2: List[tuple or None] = [None] * ((x_number_of_points - 1) * 2)
  135.  
  136. counter = 0
  137. for x_index in range(x_number_of_points - 1):
  138.  
  139. x_faces_1[counter * 2] = ((top_vertices[x_index, 0],
  140. bottom_vertices[x_index, 0],
  141. bottom_vertices[x_index + 1, 0]))
  142. x_faces_2[counter * 2] =\
  143. ((top_vertices[x_index, y_number_of_points - 1],
  144. bottom_vertices[x_index + 1, y_number_of_points - 1],
  145. bottom_vertices[x_index, y_number_of_points - 1]))
  146.  
  147. x_faces_1[counter * 2 + 1] =\
  148. ((top_vertices[x_index + 1, 0],
  149. top_vertices[x_index, 0],
  150. bottom_vertices[x_index + 1, 0]))
  151. x_faces_2[counter * 2 + 1] =\
  152. ((top_vertices[x_index, y_number_of_points - 1],
  153. top_vertices[x_index + 1, y_number_of_points - 1],
  154. bottom_vertices[x_index + 1, y_number_of_points - 1]))
  155. counter += 1
  156.  
  157. # Add faces along the edge of the model to close it. These faces are parallel
  158. # to the y-axis
  159. y_faces_1: List[tuple or None] = [None] * ((y_number_of_points - 1) * 2)
  160. y_faces_2: List[tuple or None] = [None] * ((y_number_of_points - 1) * 2)
  161.  
  162. counter = 0
  163. for y_index in range(y_number_of_points - 1):
  164.  
  165. y_faces_1[counter * 2] = ((top_vertices[0, y_index],
  166. bottom_vertices[0, y_index + 1],
  167. bottom_vertices[0, y_index]))
  168. y_faces_2[counter * 2] =\
  169. ((top_vertices[x_number_of_points - 1, y_index],
  170. bottom_vertices[x_number_of_points - 1, y_index],
  171. bottom_vertices[x_number_of_points - 1, y_index + 1]))
  172.  
  173. y_faces_1[counter * 2 + 1] = ((top_vertices[0, y_index],
  174. top_vertices[0, y_index + 1],
  175. bottom_vertices[0, y_index + 1]))
  176. y_faces_2[counter * 2 + 1] =\
  177. ((top_vertices[x_number_of_points - 1, y_index + 1],
  178. top_vertices[x_number_of_points - 1, y_index],
  179. bottom_vertices[x_number_of_points - 1, y_index + 1]))
  180. counter += 1
  181.  
  182. # Combine all the faces
  183. all_faces = top_faces + bottom_faces +\
  184. x_faces_1 + x_faces_2 +\
  185. y_faces_1 + y_faces_2
  186. model = mesh.Mesh(np.zeros(total_number_of_faces*4, dtype=mesh.Mesh.dtype))
  187.  
  188. # Create the model
  189. for index, face in enumerate(all_faces):
  190. for vertex_index in range(3):
  191. model.vectors[index][vertex_index] = np.array([face[vertex_index].x,
  192. face[vertex_index].y,
  193. face[vertex_index].z])
  194.  
  195. # Print model properties
  196. volume, cog, inertia = model.get_mass_properties()
  197. print("Volume of the model = " + str(volume))
  198. print("Centre of gravity of the model [x, y, z] = " + str(cog))
  199. print("Mass moment of inertia matrix at centre of gravity =\n" + str(inertia))
  200.  
  201. # Save the model
  202. model.save(output_filename)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement