Currently I am either creating rectangles and squares or finding rectangles and squares for tile scripts I am working on.
I noticed there are no create rectangle methods in RS. Currently I either use the polygon method or interp curve through points, but I wish there was a rectangle method. Like:
Getrectangle returns the number of squares and rectangles in the document
GetRectangleSize returns the length and width dimensions of a rectangle
Maybe I missed it and it’s there? Thanks for any hints or scripting tips to deal with creating and finding squares and rectangles.
Hi Roland- you can make your own reusable function using AddPolyline, right? GetRectangle returns the four points, and you can just feed those directly to AddPolyline
Call MakeRectangle() Sub MakeRectangle() Dim apts apts = Rhino.GetRectangle() If Not isArray(aPts) Then Exit Sub Rhino.AddPolyline array(apts(0), apts(1), apts(2), apts(3), apts(0)) End Sub
Thanks Pascal that helps. Any ideas on finding rectangles in a document?
Hi Roland, as you’re looking for ideas perhaps something along the lines of
GetObjects ( const 4 for curves, select=false) - iterate through the array if present
- IsPolyLine - IsCurveClosed - ObjectGripCount (is 4) - IsCurvePlanar
- then EnableObjectGrips - ObjectGripLocations for coords EnableObjectGrips false
- measure perimeter lengths for comparison and diagonals for squareness
- select the result if square or rectangle or both depending on which conditions are met.
Hi Roland- I’d do a search for closed polylines that have four segments, then some kind of filtering of those - check for planarity and maybe a check of curve area against a rectangle that has the same length sides as segments one and two, something like that…
Thanks Brian and Pascal.
I was afraid of all that, sure wish Dale would implement a method to check for rectangles.
Thanks for the quick suggestions.
Something like this: Function FindRectangles() FindRectangles = Null Dim aCrv: aCrv = Rhino.ObjectsByType(4) If Not isArray(aCrv) Then Exit Function Dim apts, sCrv, aRectangles(), n n = 0 For Each sCrv In aCrv If Rhino.IsObjectNormal(sCrv) Then If Rhino.IsPolyline(sCrv) Then If Rhino.IsCurveClosed(sCrv) Then If Rhino.IsCurvePlanar(sCrv) Then apts = Rhino.PolylineVertices(sCrv) If Ubound(aPts) = 4 Then If Rhino.Distance(aPts(0), aPts(2)) - Rhino.Distance(aPts(1), aPts(3)) < Rhino.UnitAbsoluteTolerance() Then ReDim Preserve aRectangles(n) aRectangles(n) = sCrv n = n + 1 End If End If End If End If End If End If Next If n > 0 Then FindRectangles = aRectangles End Function
Thanks Pascal very cool I’ll give that a try.
Hey Roland, all,
Below is a Python definition (which you can just add to your scripts) which has a few more options. If you just pass GetRectangles() with no arguments, it should return all the rectangles in the document. You can also pass in optional arguments to get rectangles by length and/or area, with a tolerance (for length and area) and whether you want to select them or not.
The criteria used to determine “rectangularity” are 2 sets of opposite sides the same length plus two diagonals the same length. It should also select rectangular curves that are not polylines but could become so if simplified.
Edit: just added an optional “square” argument. When passed as True, will only get squares (within tolerance). If omitted or False, both squares and rectangles will be selected.
Anyway, FWIW… --Mitch
import rhinoscriptsyntax as rs import Rhino def GetRectangles(length=None, area=None, square=False, tolerance=None, select=True): crvIDs=rs.ObjectsByType(4,state=1) if not crvIDs: return matches= absTol=rs.UnitAbsoluteTolerance() angTol=rs.UnitAngleTolerance() if tolerance==None: tolerance=absTol redraw=rs.EnableRedraw(False) for crvID in crvIDs: if rs.IsCurveClosed and rs.IsCurvePlanar: crv=rs.coercecurve(crvID) if not crv.IsClosed or not crv.IsPlanar: continue rc, polyline=crv.TryGetPolyline() if not rc: continue if polyline.SegmentCount==4: if length: if abs(polyline.Length-length)>tolerance: continue pts=[pt for pt in polyline] d1=pts.DistanceTo(pts) d2=pts.DistanceTo(pts) d3=pts.DistanceTo(pts) d4=pts.DistanceTo(pts) diag1=pts.DistanceTo(pts) diag2=pts.DistanceTo(pts) if abs(d1 - d3)<tolerance and abs(d2 - d4)<tolerance: if abs(diag1 - diag2)>tolerance: continue if square: if abs(d2-d1)>tolerance: continue if area: if abs((d1*d2) - area)>tolerance: continue matches.append(crvID) if select and len(matches)>0: rs.UnselectAllObjects() rs.SelectObjects(matches) rs.EnableRedraw(redraw) return matches
Thanks Mitch very nice of you it looks like yours checks for parallelograms?
Pascal many thanks for the function it works really well. One thing I need to tune in it is I need to exclude parallelogram rectangles.
Thanks again for all the help guys.
Pascal’s script checks the two diagonals for equal length. This will effectively exclude parallelograms, but it may however include trapezoids that have two opposite equal length sides, as the diagonals of those will also have the identical length.
I check first for two sets of equal length opposite sides, then I check the diagonals. That should exclude both trapezoids and parallelograms (if my reasoning is correct).
Maybe this is the ticket…