Thanks all for your replies, the shrinkfaces works nicely and that spurred me on to manage to get what I needed.

I’ve updated the script quite a bit to achieve what I want below. It now strips out points and works on rotation. The code I’m afraid isn’t very pretty but it does achieve what I wanted, I’m hoping the clean code will come with practice. I’ve left all the debug/learning bits in so it may of be some use to someone else who is just picking up this all up.

If anyone has any better ideas of how to achieve the same results especially with all the angle calculations I would gladly hear them. This took a while to work out and it feels like there must be a neater solution.

```
import rhinoscriptsyntax as rs
import math
def DivideSurface(GroupName):
brepId = rs.GetObject("Pick surface to divide",rs.filter.surface)
if not brepId: return
rs.SelectObject(brepId)
rs.Command("_Reparameterize A _Enter")
rs.Command("_SelNone")
brep = rs.coercebrep(brepId)
brep.Faces.ShrinkFaces()
srf = brep.Faces[0]
#udiv = rs.GetInteger("Number of Divisions in U",10)
#vdiv = rs.GetInteger("Number of Divisions in V",10)
spacing = 250
offset = 750
spacing = rs.GetInteger("Spacing:",500)
offset = rs.GetInteger("Offset:",650)
u = rs.SurfaceDomain(srf,0) # Get length/width of surface
v = rs.SurfaceDomain(srf,1) # Get length/width of surface
# Calculate the number of points we want to divide our surface into
udiv = int(round(abs(max(u)/spacing))) + 1# Make sure its positive abs(), coords can be -ve
vdiv = int(round(abs(max(v)/spacing))) + 1
# Calculate spacing between points
spaceu = abs((u[1]-u[0])/(udiv+1))
spacev = abs((v[1]-v[0])/(vdiv+1))
# Calculate length of grid
gridu = udiv * spaceu
gridv = vdiv * spacev
# First get boundary points to find which way the surface is
pt0 = rs.EvaluateSurface(srf,u[0], v[0])
pt1 = rs.EvaluateSurface(srf,u[0], v[1])
pt2 = rs.EvaluateSurface(srf,u[1], v[1])
pt3 = rs.EvaluateSurface(srf,u[1], v[0])
ptc = rs.EvaluateSurface(srf,u[1]/2, v[1]/2)
ptu = rs.EvaluateSurface(srf,u[1]/2, v[1]+500)
ptv = rs.EvaluateSurface(srf,u[1]+500, v[1]/2)
rs.AddLine(pt0,pt1)
rs.AddLine(pt1,pt2)
rs.AddLine(pt2,pt3)
rs.AddLine(pt3,pt0)
rs.AddPoint(pt0)
rs.AddPoint(pt1)
rs.AddPoint(pt2)
rs.AddPoint(pt3)
rs.AddPoint(ptc)
rs.AddText("0",pt0,height=250)
rs.AddText("1",pt1,height=250)
rs.AddText("2",pt2,height=250)
rs.AddText("3",pt3,height=250)
rs.AddText("C",ptc,height=250)
rs.AddText("U",ptu,height=250)
rs.AddText("V",ptv,height=250)
# Get Angle to determine if we need to rotate offset
rAngle1 = rs.Angle(pt0,pt1) # u
rAngle2 = rs.Angle(pt0,pt3) # v
rAngle3 = rs.Angle(pt0,pt2) # h
print("Angle 1: " + str(rAngle1[0]) + "Angle 2: " + str(rAngle2[0]) + " Angle 3: " + str(rAngle3[0]))
# Check whether the object is rotated too far on axis to get
rAngle = rAngle2[0]
dAngle = math.radians(rAngle)
uoffset = (((u[1]-u[0])/2) - (gridu/2))
voffset = (((v[1]-v[0])/2) - (gridv/2))
print("Uoffset: " + str(uoffset) + " Voffset: " + str(voffset) + " Angle: " + str(math.cos(dAngle)))
print(rAngle)
if rAngle > 1:
# Calc hypo of offset
h = math.sqrt(pow(uoffset*2,2) + pow(voffset*2,2))
newang = rAngle + (90 - math.degrees(math.atan(voffset/uoffset)))
# Generate offsets
uoffset = abs((h * math.sin(math.radians(newang)))/2)
voffset = abs((h * math.cos(math.radians(newang)))/2)
print("rAngle: " + str(rAngle) + " Tan Angle: " + str(math.degrees(math.atan(uoffset/voffset))))
print(" Hypotenuse: " + str(h) + " Angle: " + str(newang))
# Pt0 should be bottom left hand one
# Check u condition
if abs(pt0[0]) > abs(pt2[0]):
print("Flipping u")
uoffset = -uoffset
# Check v condition
if abs(pt0[1]) < abs(pt2[1]):
print("Flipping v")
voffset = -voffset
# Debug Print
print("Point 0: " + str(pt0[0]) + " , " + str(pt0[1]))
print("Point 1: " + str(pt1[0]) + " , " + str(pt1[1]))
print("Point 2: " + str(pt2[0]) + " , " + str(pt2[1]))
print("Point 3: " + str(pt3[0]) + " , " + str(pt3[1]))
print("Angle Between Them: " + str(rAngle) + " Deg: " + str(dAngle))
print("U Length: " + str(u[1]) + " Divisions: " + str(udiv) + " Spacing: " + str(spaceu) + " Grid Size: " + str(gridu) + " Uoff: " + str(uoffset*2))
print("V Length: " + str(v[1]) + " Divisions: " + str(vdiv) + " Spacing: " + str(spacev) + " Grid Size: " + str(gridv) + " Voff: " + str(voffset*2))
# Create points list
pts = []
# Turn off redraw - otherwise routine is very slow
rs.EnableRedraw(False)
n = 0
# Divide our surface up based on number of points required
# First loop through points on row then each column
# Function
for i in range(0, udiv, 1):
for j in range(0, vdiv, 1):
# Keep track of total points
n = n + 1
# Work out point coordinates
pt = (i/(udiv+1),j/(vdiv+1),0)
# Converts a normalized surface parameter to a surface parameter; one within the surface's domain.
srfP = rs.SurfaceParameter(srf,pt)
# Evaluates a surface at a U,V parameter.
newpt = rs.EvaluateSurface(srf,srfP[0],srfP[1])
# Creates a translation transformation matrix.
# Move it on the surface only so we can test whether the point is on the surface
matrix = rs.XformTranslation((uoffset,voffset,0))
# Transforms a 3-D point.
newpt = rs.PointTransform(newpt, matrix)
# Test whether this point is on the surface
test = rs.IsPointOnSurface(srf,newpt)
if test:
# Create a matrix to move AFFL
matrix = rs.XformTranslation((uoffset,voffset,750))
# Transforms a 3-D point.
newpt = rs.PointTransform(newpt, matrix)
# Add the new point to our list
pts.append(rs.AddPoint(newpt))
print("Points: ", str(len(pts)), " Not on surface: ", str(n-len(pts)))
# Turn on redraw
rs.EnableRedraw(True)
# Check if GroupName is not empty, if it isn't automatically rename our group
if GroupName:
grpname = rs.AddGroup(GroupName)
else:
strgrpname = rs.StringBox("Name of calculation:")
grpname = rs.AddGroup(strgrpname)
print("Group added: " + str(grpname))
rs.AddObjectsToGroup(pts, grpname)
return pts, grpname
DivideSurface("")
```

Screenshot of it working below: