Math / geometry help

unhandled

#1

I am trying to find the size / angle of an inset rectangle, and I can’t seem to figure out how I can do it:

I have a bounding quadrilateral, who’s size is known. I want to place a rectangle with one known dimension (width) in the bounding quadrilateral so that one corner of the inset rectangle hits each edge of the bounding quadrilateral. The angle and length of the inset rectangle can change as required.

Anyone have any suggestions on how to solve this?

Thanks,
Sam


#2

Grasshopper --> Galapagos
:wink:

would that be an acceptable method?


#3

Well, I got that working, thanks for the suggestion. It is a bit slow, and a bit “fuzzy”, but certainly better than doing by hand. I would love to know if there is a way to solve this though.

Sam


#4

there was a thread here a couple of years ago asking for a solution to the exact same problem.
nobody cracked it via geometric moves.


#5

#6

I ended up needing to do it with 3D objects (irregular boxes, basically) and it was a NIGHTMARE eyeballing them all. It was for interior structure for this sculpture:


#7

Construction photo of the interior. All that cross-bracing required this.


Heath's Giraffe
#8

Thanks for digging this up. At least I feel a little less disappointed in myself I couldn’t solve it mathematically. I’ll give David’s solution a look as well, it’s a bit more streamlined than mine, so might be faster.

Oh, and “Hi!” to @heath :wave:, haven’t seen you in a while.

Thanks again!
Sam


#9

OK … I had some time and … could not resist … I had to try to script that. :wink:
Obviously by iteration. Until an acceptable result is found.
( Furthermore I think it might be a useful tool for me :slight_smile: )

After a lot of mistakes and confusion …
This one (still quite empirical … ) seems to work here …

Ah, it only can work on the XY plane. :blush:

import Rhino
import math
import rhinoscriptsyntax as rs
import scriptcontext

def betavecs( p0, p1, p2 ):
  be = abs( Rhino.Geometry.Vector3d.VectorAngle( ( p0 - p1 ), ( p2 - p0 ) ) )
  if be > math.pi:
    be = math.pi * 2 - be
  be *= 0.5 
  v1 = p1 - p0
  v1.Unitize()
  v2 = p2 - p0
  v2.Unitize()
  return ( be, v1, v2 )

def line( p0, be, v1, v2, wd, al ):
  la = wd * math.sin( be - al ) / math.sin( be * 2.0 )
  lb = wd * math.sin( be + al ) / math.sin( be * 2.0 )
  aa = p0 + v1 * la
  bb = p0 + v2 * lb
  cc = ( aa + bb ) * 0.5
  ve = v1 + v2
  ve.Unitize()
  ve.Rotate( - al, Rhino.Geometry.Vector3d.ZAxis )
  lin = Rhino.Geometry.Line( cc, ve )
  return lin

def guessalpha( p0, v1, v2, pt ):
  bi = v1 + v2
  ve = pt - p0
  al = Rhino.Geometry.Vector3d.VectorAngle( ve, bi )
  if al < 0.0:
    al += math.pi * 2.0
  cp = Rhino.Geometry.Vector3d.CrossProduct( ve, bi )
  if cp.Z < 0.0:
    al = -al
  return al

def main():
  p0a = rs.GetPoint( 'First vertex ?' )
  if not p0a:
    return
  p1a = rs.GetPoint( '(First vertex) Point on one side ?' )
  if not p1a:
    return
  p2a = rs.GetPoint( '(First vertex) Point on the other side ?' )
  if not p2a:
    return
  p0b = rs.GetPoint( 'Second vertex ?' )
  if not p0b:
    return
  p1b = rs.GetPoint( '(Second vertex) Point on one side ?' )
  if not p1b:
    return
  p2b = rs.GetPoint( '(Second vertex) Point on the other side ?' )
  if not p2b:
    return
  wd = rs.GetReal( 'Rectangle fixed width ?' )
  if not wd:
    return
# tol = rs.GetReal( 'Tolerance ?' )
  tol = scriptcontext.doc.ModelAbsoluteTolerance

  cp = Rhino.Geometry.Vector3d.CrossProduct( ( p0a - p1a ), ( p2a - p0a ) )
  if cp.Z > 0.0:
    p1a, p2a = p2a, p1a
  
  cp = Rhino.Geometry.Vector3d.CrossProduct( ( p0b - p1b ), ( p2b - p0b ) )
  if cp.Z > 0.0:
    p1b, p2b = p2b, p1b

  bea, v1a, v2a = betavecs( p0a, p1a, p2a )
  beb, v1b, v2b = betavecs( p0b, p1b, p2b )

  ala = guessalpha( p0a, v1a, v2a, p0b )
  alb = guessalpha( p0b, v1b, v2b, p0a )
  while True:
    scriptcontext.escape_test()
    lina = line( p0a, bea, v1a, v2a, wd, ala ) 
    linb = line( p0b, beb, v1b, v2b, wd, alb ) 
    dis = lina.DistanceTo( linb.From, False )
    print( '%.3f' % dis )
    if dis < tol:
      break
    nala = guessalpha( lina.From, v1a, v2a, linb.From )
    nalb = guessalpha( linb.From, v1b, v2b, lina.From )
    ala = ( ala + nala ) * 0.5
    alb = ( alb + nalb ) * 0.5

  lin = Rhino.Geometry.Line( lina.From, linb.From )
  tan = lin.UnitTangent
  ve = Rhino.Geometry.Vector3d( -tan.Y, tan.X, 0.0 )
  pli = []
  pli.append( lin.From + ve * wd * 0.5 )
  pli.append( lin.From - ve * wd * 0.5 )
  pli.append( lin.To - ve * wd * 0.5 )
  pli.append( lin.To + ve * wd * 0.5 )
  pli.append( lin.From + ve * wd * 0.5 )
  print( 'Rectangle is long %.3f' % lin.Length )

  scriptcontext.doc.Objects.AddPolyline( pli )
  scriptcontext.doc.Views.Redraw()

main()

To use it, we have to pick the vertex points plus one point on each side … twice for the two vertices …

Regards


#10

nice one @emilio

it gets these tries so incredibly close to being perfect that i’d deem it usable for any practical application i could see myself needing it for.
thanks!


#11

Hi Jeff

As you can see from the script, it uses Rhino’s tolerance to check when to stop the loop and return a result.
I think you can easily edit the script and use a tighter tolerance value.
( Actually the instruction to enter the tolerance value is still in the script … just commented out…
You can use it and delete the following assignment from Rhino’s absolute tolerance … :wink: )

Glad to be helpful
Thanks for the appreciation.


#12

heh, i just woke up and tried it…
definitely didn’t read through the script yet… i’ll give it another look after coffee.


#13

Hehe … right … different time zones … :smile: