Now for a simple case this is fine. But if adding or removing from some more complex shapes this becomes quite cumbersome. Especially if the original hatch is surrounding an area that is not hatched, in those cases AllRegions can’t be used.
Hello - In the current state of things, what you’re doing is it…You can try this plug-in for now and see if it helps - it is not as clean as just trimming but probably better than the ‘by hand’ work around.
Unblock the plug-in (rhp file) in Windows Explorer (right click > Properties > Unblock (lower right) and Apply) then drag and drop it onto Rhino for TrimHatch.
This is my approach on the subject, let me know what you think. Constructive criticism is welcomed
The script asks for a hatch and existing curves or blocks containing curves, then just like using CurveBoolean you can extend, trim or cut hole in the hatch by selecting the desired region.
Paste this into a button and experiment:
! _-RunPythonScript (
#HatchEdit
#This script updates an existing hatch to fill a new region defined by a selection of boundary curves or blocks containing curves
#Krausz Zsolt 20200418
import rhinoscriptsyntax as rs
import Rhino
import System.Guid
import sys
import scriptcontext as sc
import rhinoscript.utility as rhutil
string1 = "Select boundary curves or blocks"
string2 = "Select hatch to edit"
def DuplicateHatchBorder(hatch_id, outer=True):
"""Create curves that duplicate a hatch inner, outer or both borders
Parameters:
hatch_id (guid): identifier of a hatch
outer (boolean, optional): the border curves to return
True=exterior
False=interior
Returns:
list(guid, ...): list of curve ids on success
None: on error
"""
hatch = rhutil.coercegeometry(hatch_id, True)
curves = Rhino.Geometry.Hatch.Get3dCurves(hatch, outer)
if curves is None: return sc.errorhandler()
tolerance = sc.doc.ModelAbsoluteTolerance * 2.1
curves = Rhino.Geometry.Curve.JoinCurves(curves, tolerance)
if curves is None: return sc.errorhandler()
rc = [sc.doc.Objects.AddCurve(c) for c in curves]
sc.doc.Views.Redraw()
return rc
class Hatch:
def __init__(self, id):
self.id = id
self.StoreAttributes()
rs.LockObject(self.id)
def StoreAttributes(self):
# store attributes of input hatch
self.pattern = rs.HatchPattern(self.id)
self.rotation = rs.HatchRotation(self.id)
self.scale = rs.HatchScale(self.id)
#store inner and outer boundaries of input hatch
self.innerBorder = DuplicateHatchBorder(self.id, False)
self.outerBorder = DuplicateHatchBorder(self.id, True)
def GetNewBoundary(self, crvs):
rs.UnselectAllObjects()
rs.SelectObjects(crvs + self.outerBorder + self.innerBorder )
if rs.Command("_-CurveBoolean", echo=True):
self.newBorder = rs.LastCreatedObjects(select=False) #replace new border with the selected region
else: self.newBorder = self.outerBorder + self.innerBorder # in case no region is selected maintain old border
rs.UnselectAllObjects()
def RefreshHatch(self):
sn = sc.doc.BeginUndoRecord("HatchEdit")
newHatch = rs.AddHatch(self.newBorder, self.pattern, self.scale, self.rotation) # create a hatch with new boundary, same pattern attributes
rs.MatchObjectAttributes(newHatch, source_id=self.id) # match new hatch attributes with old one
rs.UnlockObjects([self.id, newHatch])
rs.DeleteObject(self.id) # delete original hatch
if (sn > 0):
sc.doc.EndUndoRecord(sn)
def DeleteTemporaryGeometry(self):
rs.DeleteObject(self.outerBorder)
rs.DeleteObjects([crv for crv in self.newBorder])
rs.DeleteObjects([crv for crv in self.innerBorder])
# ask user to select the hatch to edit
id = rs.GetObject(message=string2, filter=65536, preselect=True, select=True)
#test if selection is not empty
if id:
hatchObj = Hatch(id)
cutBoundaries = rs.GetObjects(message=string1, filter=4|4096, preselect=False, select=True)
if cutBoundaries:
hatchObj.GetNewBoundary(cutBoundaries)
hatchObj.RefreshHatch()
hatchObj.DeleteTemporaryGeometry()
else:
rs.UnlockObject(hatchObj.id)
del hatchObj
rs.Redraw()
)
Thx! Fixed the issues you pointed out. Find the updated script below:
! _-RunPythonScript (
#HatchBoolean
#This script updates an existing hatch to fill a new region defined by a selection of boundary curves or blocks containing curves
#Krausz Zsolt 2020042
#Error log
#maintains original layer for all pieces
#hatch base implemented
import rhinoscriptsyntax as rs
import Rhino
import System.Guid
import sys
import scriptcontext as sc
import rhinoscript.utility as rhutil
string1 = "Select boundary curves or blocks"
string2 = "Select hatch to edit"
def HatchBasePoint(hatch_ids, base_point=None):
#sets or returns a hatch basepoint
# test if user specified one id only
if type(hatch_ids) is System.Guid:
hatch_ids = [hatch_ids]
# initialise return values
r_count = 0
r_list = []
# go through the list
for hatch_id in hatch_ids:
rh_hatch_obj = sc.doc.Objects.Find(hatch_id)
if base_point == None:
# if no point was specified, return existing basepoint of the hatch
base_point = rh_hatch_obj.Geometry.BasePoint
base_point = rs.coerce3dpoint(base_point)
r_list.append(base_point)
else:
# if a point was specified, set it as the new basepoint of the hatch, and increase count
rh_hatch_obj.Geometry.BasePoint = rhutil.coerce3dpoint(base_point)
rh_hatch_obj.CommitChanges()
r_count = +1
#return the ids of the basepoints or the number of hatches modified
if r_count == 0 and len(r_list)>1:
return r_list
elif r_count == 0 and len(r_list) == 1:
return r_list[0]
else:
return r_count
def DuplicateHatchBorder(hatch_id, outer=True):
"""Create curves that duplicate a hatch inner, outer or both borders
Parameters:
hatch_id (guid): identifier of a hatch
outer (boolean, optional): the border curves to return
True=exterior
False=interior
Returns:
list(guid, ...): list of curve ids on success
None: on error
"""
hatch = rhutil.coercegeometry(hatch_id, True)
curves = Rhino.Geometry.Hatch.Get3dCurves(hatch, outer)
if curves is None: return sc.errorhandler()
tolerance = sc.doc.ModelAbsoluteTolerance * 2.1
curves = Rhino.Geometry.Curve.JoinCurves(curves, tolerance)
if curves is None: return sc.errorhandler()
rc = [sc.doc.Objects.AddCurve(c) for c in curves]
sc.doc.Views.Redraw()
return rc
class Hatch:
def __init__(self, id):
self.id = id
self.StoreAttributes()
rs.LockObject(self.id)
def StoreAttributes(self):
# store hatch base point
self.base_point = HatchBasePoint(self.id)
# store attributes of input hatch
self.pattern = rs.HatchPattern(self.id)
self.rotation = rs.HatchRotation(self.id)
self.scale = rs.HatchScale(self.id)
#store inner and outer boundaries of input hatch
self.innerBorder = DuplicateHatchBorder(self.id, False)
self.outerBorder = DuplicateHatchBorder(self.id, True)
def GetNewBoundary(self, crvs):
rs.UnselectAllObjects()
rs.SelectObjects(crvs + self.outerBorder + self.innerBorder )
if rs.Command("_-CurveBoolean", echo=True):
self.newBorder = rs.LastCreatedObjects(select=False) #replace new border with the selected region
else: self.newBorder = self.outerBorder + self.innerBorder # in case no region is selected maintain old border
rs.UnselectAllObjects()
def RefreshHatch(self):
sn = sc.doc.BeginUndoRecord("HatchEdit")
# create a hatch with new boundary, same pattern, scale and rotation
newHatch = rs.AddHatches(self.newBorder, self.pattern, self.scale, self.rotation)
HatchBasePoint(newHatch, self.base_point)
r = rs.MatchObjectAttributes(newHatch, source_id=self.id) # match new hatch attributes with old one
rs.UnlockObjects([self.id]+newHatch)
rs.DeleteObject(self.id) # delete original hatch
if (sn > 0):
sc.doc.EndUndoRecord(sn)
def DeleteTemporaryGeometry(self):
rs.DeleteObject(self.outerBorder)
rs.DeleteObjects([crv for crv in self.newBorder])
rs.DeleteObjects([crv for crv in self.innerBorder])
# ask user to select the hatch to edit
id = rs.GetObject(message=string2, filter=65536, preselect=True, select=True)
#test if selection is not empty
if id:
hatchObj = Hatch(id)
cutBoundaries = rs.GetObjects(message=string1, filter=4|4096, preselect=False, select=True)
if cutBoundaries:
hatchObj.GetNewBoundary(cutBoundaries)
hatchObj.RefreshHatch()
hatchObj.DeleteTemporaryGeometry()
else:
rs.UnlockObject(hatchObj.id)
del hatchObj
rs.Redraw()
)