Skip to content

Commit

Permalink
Tidy-up support module code
Browse files Browse the repository at this point in the history
  • Loading branch information
drlukeparry committed Jan 22, 2022
1 parent e438bef commit 9ee1f66
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 29 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ using a single/multi point exposure by generating a series of scan vectors in a
**Support Structure Generation**

* Projection based block and truss support structure generation

* 3D intersected support volumes are generated from overhang regions using OpenGL ray-tracing approach
* Generate a truss grid using support volumes suitable for Metal AM processes
* Exact support volume generation using the `pycork <https://github.com/drlukeparry/pycork>`_ library
* Extracting overhang surfaces from meshes

**Slicing:**
Expand Down
28 changes: 15 additions & 13 deletions pyslm/support/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import pycork

from pyslm import pyclipper
from line_profiler_pycharm import profile


def extrudeFace(extrudeMesh: trimesh.Trimesh,
height: Optional[float] = None,
Expand Down Expand Up @@ -106,29 +106,28 @@ def extrudeFace(extrudeMesh: trimesh.Trimesh,
return extMesh


def boolUnion(meshA, meshB):
def boolUnion(meshA: trimesh.Trimesh, meshB: trimesh.Trimesh):

vertsOut, facesOut = pycork.union(meshA.vertices, meshA.faces, meshB.vertices, meshB.faces)

return trimesh.Trimesh(vertices=vertsOut, faces=facesOut, process=True)


def boolIntersect(meshA, meshB):
def boolIntersect(meshA: trimesh.Trimesh, meshB: trimesh.Trimesh):

vertsOut, facesOut = pycork.intersection(meshA.vertices, meshA.faces, meshB.vertices, meshB.faces)

return trimesh.Trimesh(vertices=vertsOut, faces=facesOut, process=True)

#subprocess.call([CORK_PATH, '-isct', 'a.off', 'b.off', 'c.off'])
#return trimesh.load_mesh('c.off')

def boolDiff(meshA, meshB):
def boolDiff(meshA: trimesh.Trimesh, meshB: trimesh.Trimesh):

vertsOut, facesOut = pycork.difference(meshA.vertices, meshA.faces, meshB.vertices, meshB.faces)

return trimesh.Trimesh(vertices=vertsOut, faces=facesOut, process=True)

def resolveIntersection(meshA, meshB):

def resolveIntersection(meshA: trimesh.Trimesh, meshB: trimesh.Trimesh):

vertsOut, facesOut = pycork.resolveIntersection(meshA.vertices, meshA.faces, meshB.vertices, meshB.faces)

Expand Down Expand Up @@ -172,6 +171,7 @@ def path2DToPathList(shapes: List[shapely.geometry.polygon.Polygon]) -> List[np.

return paths


def sortExteriorInteriorRings(polyNode,
closePolygon: Optional[bool] = False) -> Tuple[List[np.ndarray], List[np.ndarray]]:
"""
Expand Down Expand Up @@ -240,23 +240,23 @@ def triangulateShapelyPolygon(polygon: shapely.geometry.Polygon,
return result['vertices'], result['triangles']

def triangulatePolygonFromPaths(exterior: np.ndarray, interiors: List[np.ndarray],
triangle_args:str = None,
triangle_args: str = None,
**kwargs):
"""
Given a list of exteiror and interiors triangulation using a
Given a list of exterior and interiors triangulation using a
python interface to `triangle.c`
.. code-block:: bash
pip install triangle
:param polygon: Polygon object to be triangulated
:param exterior: Exterior boundaries of polygon
:param interiors: Interior boundaries of polygon
:param triangle_args: Passed to triangle.triangulate i.e: 'p', 'pq30'
:param kwargs:
:return: Returns a tuple of vertices and faces
"""

# set default triangulation arguments if not specified

if triangle_args is None:
triangle_args = 'p'

Expand All @@ -268,7 +268,8 @@ def triangulatePolygonFromPaths(exterior: np.ndarray, interiors: List[np.ndarray

return result['vertices'], result['triangles']

def _polygon_to_kwargs2(exterior, interiors):

def _polygon_to_kwargs2(exterior: np.ndarray, interiors: List[np.ndarray]):
"""
Given both exterior and interior boundaries, create input for the
the triangle mesh generator. This is version #2 which has been adapted from
Expand Down Expand Up @@ -462,6 +463,7 @@ def add_boundary(boundary, start, clean=True):

return result


def triangulatePolygon(section,
closed: Optional[bool] = False) -> Tuple[np.ndarray, np.ndarray]:
"""
Expand Down Expand Up @@ -552,4 +554,4 @@ def generatePolygonBoundingBox(bbox: np.ndarray) -> shapely.geometry.Polygon:
[a[1], b[0]],
[a[0], b[0]]])

return bboxPoly
return bboxPoly
4 changes: 2 additions & 2 deletions pyslm/support/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ def visSize(self):
return self._visSize

@property
def mesh(self):
def mesh(self) -> trimesh.Trimesh:
return self._mesh

@property
def bbox(self):
def bbox(self) -> np.ndarray:
return self._bbox

def setMesh(self, mesh: trimesh.Trimesh):
Expand Down
34 changes: 21 additions & 13 deletions pyslm/support/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,11 @@ class BlockSupportGenerator(BaseSupportGenerator):
for creating the surrounding support skin.
"""

_intersectionVolumeTolerance = 50
"""
An internal tolerancces used to determine if the projected volume intersects with the part
"""

_gausian_blur_sigma = 1.0
"""
The internal parameter is used for blurring the calculated depth field to smooth out the boundaries. Care should
Expand Down Expand Up @@ -725,7 +730,6 @@ def identifySupportRegions(self, part: Part, overhangAngle: float,
"""
The geometry of the part requires exporting as a '.off' file to be correctly used with the Cork Library
"""
#part.geometry.export('part.off')

supportBlockRegions = []

Expand Down Expand Up @@ -772,6 +776,7 @@ def identifySupportRegions(self, part: Part, overhangAngle: float,
timeIntersect = time.time()

logging.info('\t - start intersecting mesh')

if False:

# Intersect the projection of the support face with the original part using the Cork Library
Expand All @@ -792,9 +797,12 @@ def identifySupportRegions(self, part: Part, overhangAngle: float,
totalBooleanTime += time.time() - timeIntersect

# Note this a hard tolerance
if cutMesh.volume < -1: # 50
if cutMesh.volume < BlockSupportGenerator._intersectionVolumeTolerance: # 50

"""
Create a support structure that extends to the base plate (z=0)
NOTE - not currently used - edge smoothing cannot be performed despite this being a
quicker methods, it suffer sever quality issues with jagged edges so should be avoided.
"""
Expand All @@ -808,7 +816,7 @@ def identifySupportRegions(self, part: Part, overhangAngle: float,

supportBlockRegions.append(baseSupportBlock)

continue # No intersection had taken place
continue # No self intersection with the part has taken place with the support
elif not findSelfIntersectingSupport:
continue

Expand Down Expand Up @@ -941,8 +949,8 @@ def identifySupportRegions(self, part: Part, overhangAngle: float,
"""
Intersecting with cutmesh is more efficient when projecting downwards
"""

if cutMesh.volume > 50:
#
if cutMesh.volume > BlockSupportGenerator._intersectionVolumeTolerance:

hitLoc2, index_ray2, index_tri2 = cutMeshUpper.ray.intersects_location(ray_origins=coords2,
ray_directions=ray_dir,
Expand Down Expand Up @@ -977,14 +985,14 @@ def identifySupportRegions(self, part: Part, overhangAngle: float,

extrudedBlock.export('b.off')

"""
Take the near net-shape support and obtain the difference with the original part to get clean
boundaries for the support
"""

subprocess.call([self.CORK_PATH, '-diff', 'b.off', 'part.off', 'c.off'])
blockSupportMesh = trimesh.load_mesh('c.off', process=True, validate=True)

"""
Take the near net-shape support and obtain the difference with the original part to get clean
boundaries for the support
"""

blockSupportMesh = boolDiff(extrudedBlock, part.geometry)
blockSupportMesh.fix_normals()
blockSupportMesh.remove_degenerate_faces()
Expand All @@ -1007,7 +1015,7 @@ def identifySupportRegions(self, part: Part, overhangAngle: float,
logging.info('\t - processed support face\n')

logging.info('Total boolean time: {:.3f}\n'.format(totalBooleanTime))
print('Total Boolean Time', totalBooleanTime)

return supportBlockRegions


Expand Down Expand Up @@ -1069,7 +1077,7 @@ def mergeMesh(self, state: bool):
self._mergeMesh = state

@property
def useSupportSkin(self) -> True:
def useSupportSkin(self) -> bool:
""" Generates a support skin around the extruded boundary of the support"""
return self._useSupportSkin

Expand Down Expand Up @@ -1124,7 +1132,7 @@ def gridSpacing(self) -> List[float]:

@gridSpacing.setter
def gridSpacing(self, spacing: List[float]):
""" The Grid Spacing used for the support structure """
""" The Grid spacing used for the support structure """
self._gridSpacing = spacing

@staticmethod
Expand Down

0 comments on commit 9ee1f66

Please sign in to comment.