Hi,
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:
Rhino.addrectangle
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.
RM
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
-Pascal
Thanks Pascal that helps. Any ideas on finding rectangles in a document?
RM
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…
-Pascal
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.
RM
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.
RM
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[1].DistanceTo(pts[0])
d2=pts[2].DistanceTo(pts[1])
d3=pts[2].DistanceTo(pts[3])
d4=pts[3].DistanceTo(pts[0])
diag1=pts[0].DistanceTo(pts[2])
diag2=pts[1].DistanceTo(pts[3])
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.
RM
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).
–Mitch
Maybe this is the ticket…