Trim a Hole in Hatch Pattern

Is there anyway to trim a hole in an existing hatch pattern without having to recreate it?

Thanks

No, but you can turn on controlpoints and edit a hatch.

I wish for a full edit too, kind of like how we edit a block would be nice.

Fastest way to edit now is to duplicate the boundry of the hatch, edit and/or add curves to that, then rehatch, and match to the old hatch, and delete the old.

Thanks. The dupBorder trick works nice.

Yes more hatch edit features would be nice.

Dennis

Also on my wishlist!

Hey djnelson75

I have been working a lot with hatches lately, and missed this function a lot, so I decided to give it a try and wrote this script that automates basicly what Holo wrote.

Let me know what you think: is it helpful? noticed any bugs? is it user friendly? is it something you would do differently? Thx for your input!

Paste text below into a new button of your liking:

! _-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()

)
2 Likes

Fixed some bugs, find the updated script below:

Zsolt

! _-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()


)
1 Like