ReJOIN: Recursive Systems and Compound Wood Joinery

Page 1

R e J O I N Recursive Systems and Compound Wood Joinery



introduction


Our research questions the traditional formation of tectonic systems and proposes a recursive based emergent system, based both on user-driven parameters and self generated awareness, as a means for future design. ReJoin investigates the possibility of design and production of interlinked wooden structures based on the constraints of structure, joinery, site, and production through recursive relationships. The research is structured around a continuous dialogue between traditional wood craft, algorithmic design technique, and digital fabrication processes, all of which inform the resultant built installation.

The project leverages L-system based computation and embedded logics of self-organization to investigate the structural abilities of wooden branching systems; a structural system distributed as a hierarchical assembly of interconnected members. By introducing an understanding of these members as autonomous entities with positionalawareness and attraction or rejection based behavior the geometric system is transformed into structures describing density and porosity, enclosure and openness, pochĂŠ and inhabitation, structure and surface. By implementing dynamic processes with recursive logic, material and production constraints, and physical prototyping of complex wooden joints, ReJoin explores how to design and construct such a system. The combination of computational

capabilities with digital fabrication allows the introduction of craft related knowledge into contemporary practice that was previously bound to the skill and knowledge of the trained craftsman. The use of the 5-axis CNC Router allows the cutting of complex multi-member compound angled joints in high speed and variable geometry which allows for mass customization of parts and easier assembly. Thus the proposed system mediates between site conditions, formal design intentions, tectonic needs, and production processes while creating a responsive connection between the conceptual and its physical manifestation.


Step 0: Initial Line

Branching Recursion : How It’s Made

Step 1: Rotate C0 around its start point and the Z-axis

Step 2: Copy C01 from its start point to its end point

C0

Step 3: Create a reference line along the X-axis

Step 4: Move that reference line (C2) to the start point of C1

C0 C01

Y

Y

C01

Y

C1

C1

Y

Y

C2

C0

Plan View

C2

X

X

X

Plan View

Plan View

Plan View

X C0

Plan View

C01

C1

C01

X

Plan View

C1

C1 C3

Z Y

Branching Recursion : How It’s Made

Axon View

Step 0: Initial Line Step 4: Move that reference line (C2) to the start point of C1 Step 7: Rotate C5 around the Z-axis at a random angle between 0˚- 360˚

Step 3: Create a reference line along the X-axis

Step 1: Rotate C0 around its start point and the Z-axis Step 8: Scale C6 to .65 its original length

C01

Y

C01

Y

C1

C1

Y

X

Plan View C1

C01

C01 C7

Y

C1

C01

Y

Y

Y

X

Step 2: Copy C01 from its start point to its end point Step 9: Move C7 back to its final destination at the end of C0

C0

C01 C7

Y

Y

X

Y

X

Plan View Plan View

C01

C7

C1

C0

C01

C1

Y C0

Plan View Plan View

C0

C6

Plan View

X

C1

Random

C7

Plan View C1

C5

Plan View

C6 C7

C1

Scale

C7

X

Axon Vie

Awareness: If a branch’s endpoint falls within X” from another endpoint, repeat steps 1-10

C0

C0 C0

C0 C0

C0

C0

C0

C0

C0

C0

C5 Random Radius = scalefactor x length C4 of C0 x .65

C4

C3

Y X

Axon View Axon View

C0

Plan View

Plan View

Y Z Y

X

C0

60˚

C0

C2 X

C0

X

X

C8

Plan View

C0

Y

Step 11: Select every C0, place in a list, and randomly select a new line for branching until the tree reaches 100 total lines

C5

Y

Y

X

Z Z Y

Y

C0 C7

C4

Y

C0

C3

Axon View Axon View

C0 X

C1

X

Step 10: Repeat until C0 Length < X

Plan View

Z

C2 X

Axon View

C0 C0

Y

X

C0

Axon View Axon View

Step 6: Rotate C4 up at a random angle between 30˚- 60˚ Loft circles at the start, mid, and end points of C0

X

30˚

Z

X

X

C2

C0

C0

Z Y

Y

C0

C2

C0

Plan View

C6

Y

C0 X

Plan View

C0 C1

Random

C3

Y

C0

C2

C0

Plan View

C5

X

Step 5: Rotate C1 around its start point and the Y-axis until it is parallel toStep the plane 9: Move back to its final destination at the end of C0 Awareness: If a branch’s endpoint falls within X” from another endpoint, repeatC7steps 1-10

C3

Y C0

360˚

C1

C1

Y C0

Z

Axon View

C6 C0

C5

Y

X

C0

C7 C1

Axon View Axon View

C0

C2

Z

X

X

Axon View

C0 C0

X

C4

Y

Y X

Axon View Axon View

Step 4: Move that reference line (C2) to the start point of C1 Step Scale C6 until to .65 its original length Step 7: Rotate C5 around the Z-axis at a random angle between 0˚- 360˚ Step 11: Select every C0, place in a list, and randomly select a new line for8:branching the tree reaches 100 total lines

C0

X

Y

C2 X

X

C7

Z

Z

Z

Y

Y X

C0

Y X

C8

Y

Axon View

Step 3: Create a reference line along the X-axis Step 10: Repeat until C0 Length < X

C6

Z

Y

Axon View

Axon View

C01

Scale

Z

C5

Y

60˚

C4

Z

C2 X

X

X

Axon View

C0

Z

Z

C1

C7

X

Plan View Plan View

C0

C1

C7

C01

X

Plan View

C3

Z

Step 5: Rotate C1 around its start Awareness: If a branch’s 1-10

Step 4: Move that reference line (C2) to the start point of C1 Step 11: Select every C0, place in a list, and randomly select a new line for branching until the tree reaches 100 total lines

C0

Y C8

Plan View Plan View

C6

Y

X

X C0

C5

Z

C4

Y

X

X

Plan View

Random

C1

C0

Y C2

X

Plan View Plan View

C6 C01

C3

Y

C5 X

360˚ C0

Plan View

Axon View

Step 3: Create a reference line along the X-axis Step 10: Repeat until C0 Length < X

Step 6: Rotate C4 up at a random angle between 30˚- 60˚

C6

Y

X

Plan View

Y C2 X

Axon View

C0

Y C2

X

Plan View

Axon View

Step C01 from its start point to its end point Step 5: Rotate C1 around its start point and the Y-axis until it is parallel to 2: theCopy plane Step 9: Move C7 back to its final destination at the end of C0

C0 C6

C0

Y C2 X

X

Axon View

C0

Z

Y

X

X

Axon View

Step 2: Copy C01 from its start point to its end point

Z

Y

Y

X

Rotate C0 around its start point and the Z-axis

Z

Z

Z

30˚

Radius = RandomWithinRange (.5 x Top to Bottom) Z

Z

Z Y

Y

X

Axon View Axon View

ove C7 back to its final destination at the end of C0

Step 10: Repeat until C0 Length < X

Z Y

Y

Y

C7

Z

Z

Y

Y

Y

Axon View Axon View

Axon View

Axon View

Awareness: If a branch’s endpoint falls within X” from another endpoint, repeat steps 1-10

Axon View

Loft circles at the start, mid, and end points of C0

C0 C0

C0

C0

C0

C0

C0

C0

C7 Radius = scalefactor x length of C0 x .65

Radius = RandomWithinRange (.5 x Top to Bottom)

Z

Z

Z

Z

Y

Y

Y

Y

Y

X

X

X

X

X

Axon View

Axon View

Axon View

Early recursive branching script.

Axon View

Z

Y

X

X

X

C0 C0

C0

C0

Y

Y

Axon View Axon View

C0

C0

Z

Z

Z

X

X

X

Step 11: Select every C0, place in a list, and randomly select a new line for branching until the tree reaches 100 total lines

X

Plan View

Z

C2 X

X

X

C0

Y C8

Y

Axon View Axon View

C0

C0

Z

C2 X

X

Z

Radius = scalefactor x length of C0

Axon View

Z Y

Radius = scalefactor x length of C0

X

Axon View Axon View

Z

Z

Y

Y

X

X

Axon View

Y

X

Axon View

Axon View


It is without question that technology is having a profound impact on the field of Architecture, whether it is through design research, digital fabrication, parametric design, or environmental simulation, the long-term effects of these shifts are only beginning to become apparent. An area where the status quo of architectural production is being challenged by the advancements of technology is the transformation, or in some cases abandonment, of centuries old techniques of design and representation. In her book Digital Fabrications: Architectural and Material Techniques, Lisa Iwamoto states that: “architecture continually informs and is informed by

its modes of representation and construction, perhaps never more so than now, when digital media and emerging technologies are rapidly expanding what we conceive to be formally, spatially, and materially possible. Digital fabrication, in particular, has spurred a design revolution, yielding a wealth of architectural invention and innovation.” These new techniques offer the architect more freedom in the design process, yet they require a body of knowledge that has been absent from architecture’s required studies until recently: scripting, parametric design, and digital fabrication. For many years, the use of the computer in architecture simply replaced the pencil and paper as a tool,

while making very little impact on the design process, but with exponentially increasing computer power and access in architecture schools to advanced robotic fabrication this has changed. As we move forward in an age where digital technologies are revolutionizing both the way that architectural ideas are conceived of and represented, and the means by which those ideas are ultimately constructed, the advancements of these digital tools “offer new and up until now unimaginable venues and possibilities for openness and participation by even nontechnical agents in all stages of design,” while it requires the architect to regain some of the craftsman knowledge that it gave away over the course of history.


Early test of a compound joint being cut from layered birch plywood on Taubman College’s 5-axis CNC router. The test revealed limitations in the relationship between the material and the tool.


In his book, The Alphabet and The Algorithm, Mario Carpo asserts that there has been a paradigm shift in the dissemination of architectural ideas from an allographic Albertian framework of notational drawings and replication from drawing to building, to an autographic, pre-Albertian notion of designer-craftsman, that supports mass customization through algorithmic design. Within this scope of practice, the architect retains not only authorship of design, but also more control over production. While this may be true at the current state of technological availability, Carpo speculates that the invention of internetbased shared authorship, or cloud computing, combined with algorithmic design geared towards personalized

parameter based products, may in fact lead the architect to take a secondary role as designer, subservient to the algorithm, or “objectile�. Thus, a secondary component to our research is to investigate the effectiveness of translating a craft-based, bottom-up approach into the architectural design studio. To avoid some of the downfalls dealing with complexity of detailed design with multiple parameters inherent in a topdown hierarchical design approach, we have structured our studio as a bottom-up environment. Generative interactive procedures reveal a process of design with direct dialogue with, and feedback to, the process of making which in turn

reveals new information important to the design, creating a circular process of materialization.




joint development


Initial studies began with an intense investigation in compound joint possibilities. The purposes of this were manifold, and included developing an understanding of what the limitations of material properties, machine capabilities, and construction techniques might be. Joint types were grouped into categories, which were frequently referred to as “planar”, “interlocking”, “nested”, and “mortise-and-tenon”. Once a sufficient amount of each type were designed and modeled, the most refined option of each category was taken into Mastercam software where toolpaths were set up to be physically tested from birch plywood on Taubman College’s 5-axis CNC router.


Compound Joinery Taxonomy Physically Produced

Nate Anderson // Jimmy Bevilacqua // Cam Stewart

Requires External Fasteners

Non-Heirarchical Assembly

Planar b

c

b c

Axon a a

2

1 Exploded b b

c

c

Assembled a 1

2

3

4

5

a

6 5

6

Interlocking d c

Axon

b

Elevation

a

d c

Plan (Exploded)

b

a Plan (Assembled) 1

2

3

4

5

6

7

7


Nested

d c

Axon b

Elevation a d

c

b Plan (Exploded)

Plan (Assembled) a 1

2

3

4

5

6

7

7

Mortise-and-Tenon d

Axon

c

b

Elevation a

d c

Plan (Exploded)

b

Plan (Assembled) a

1

2

3

4

5

6

7

7


Edge-to-Face

c

d

C

b

Axon

D/a

B

A

Elevation

d

c

b

C

Plan (Exploded)

D/a

B

Plan (Assembled) A 1

2

3

4

5

6

7

7

Recursive Branching Script Step 0: Initial Line

Branching Recursion : How It’s Made

Step 2: Copy C01 from its start point to its end point

Step 1: Rotate C0 around its start point and the Z-axis

C0

Step 3: Create a reference line along the X-axis

C01

Y

Y

C01

Y

C1

C1

Y

C0

Plan View

C3

Y

C2 X C0

Plan View

Step 5: Rotate C1 around its start point and the Y-axis until it is parallel to the plane

Step 4: Move that reference line (C2) to the start point of C1

Y

X

X

X

X

Plan View

Plan View

Plan View

Plan View

C01

C1

C1

Z

Z

Y

Y

X

X

Step 9: Move C7 back to its final destination at the end of C0

Step 8: Scale C6 to .65 its original length

Step 7: Rotate C5 around the Z-axis at a random angle between 0˚- 360˚

X

C6 C7

C5

C0

Loft circles at the start, mid, and end points of C0

C0 C0

C0

C0

C0

C0

C0

Plan View

Awareness: If a branch’s endpoint falls within X” from another endpoint, repeat steps 1-10

Axon View

C0

C0 C0

X

C8 C0

Plan View

X

Axon View

C0 C0

Y

Y

X

Plan View Random

Y

X

Axon View

C0 C7

C7

C5

Y

C6

Y

Y C2 X

Step 11: Select every C0, place in a list, and randomly select a new line for branching until the tree reaches 100 total lines

C0

C4

Z

Z

Axon View

Step 10: Repeat until C0 Length < X

C6

C6

360˚

Y

Axon View

Axon View

C5 C4

Z

C2 X

X

Axon View

Axon View

X 60˚

C1

C1

Z

Y

Y

X

C0

C7

Scale

Radius = scalefactor x length of C0 x .65

Radius = RandomWithinRange (.5 x Top to Bottom)

Z

Z

Z

Z

Z

Z

Z

Y

Y

Y

Y

Y

Y

Y

X

X

X

X

X

X

X

Axon View

Axon View

Axon View

Axon View

C5

Y

C2

X

C3

Z

C4

Plan View C01

Z

Step 6: Rotate C4 up at a random angle between 30˚- 60˚

C0

Axon View

Axon View

Radius = scalefactor x length of C0

Axon View

Random

30˚

Plan View



While most of the initial joint tests failed in producing functioning physical compound joints, an enormous amount of knowledge was gained and a foundation was built around grasping the back-and-forth relationships in moving between digital design space, digial toolpath output, and CNC methodology. Understanding drillbit types and speeds, drill orientation and spin, vacuum strength, G-Coding, and toolpath modeling are all critical in producing even a single successful physical piece, and the learning curve for this was steep. Initial tests proved invaluable in beginning to grasp these techniques.


Second and third generations of physically produced “branches� increased in success rate and honed in on an aesthetic that was being tailored while also testing for new limitations, including length and size. Joint types evolved to become more producible and reproducible.


Second Generation

Second Generation

Edge-to-Face / Mortise-and-Tenon

Second Generation

Interlocking

Mortise-and-Tenon

Axon

Elevation

Plan (Exploded)

Plan (Assembled)

1

2

3

1

2

3

4

Second Generation

Second Generation

2

3

Second Generation

Interlocking

Edge-to-Face /D Mortise-and-Tenon

1

Mortise-and-Tenon

D

C

C

B B

A

B

C

A

A

A

B

C

D

A

B

C A

B

C

D



recursive scripting


A simultaneous component to joint testing was developing a script that would produce a networked tree-like system that recursively developed the properties of each individual branch and node as it applied to its relationship within the system. The script was broken into two components, one that produced the network of lines in place, and another that turned those lines into the three dimensional members that would then be physically produced.

having each new member created “search” for another member within a cone of vision. If another member was within this cone, the ends of each member would snap together, and growth would cease at this node. Input surfaces were also embedded into the logic of the script such that any desired surface would prevent the further growth of any branch that intersects it. This allows one to shape the output network to any desired condition.

The first script produces a growing network of branches, where the end of each branch, if unobstructed, produces 3 new branches until a certain height is reached. Additionally, stabilizing tendencies were embedded into the script by

Once this network is created, the latter script transforms each singular line into a fully-realized, three dimensional member that appropriately positions its joint in relation to the members around it. While four members come

together to produce one compound joint, each member has a different geometric shape, depending on its position within the joint, and the script’s embedded logic accounts for this. Once the final tree is produced, the script labels and lays out each member within a digital “stock”, from which its toolpaths can be developed. The process is streamlined such that manual labor and calculation is minimized and even eliminated.

Final ReJoin Script Logics def FieldofPoints ( ):

1. Starting Ground

Select a surface as a ground condition

2. Select Areas to Avoid

Select Designated Areas where voids are desired

3. Select Paths

4. Construct Field of Points

Select curves that represent circulation routes

A grid of starting points are set up based on U and V spacing

6. Move Points

5. Remove Points

7. Give points a starting identity

Move points away from paths based on a factor of the inverse of distance from the two nearest paths

Delete points from areas designated to avoid

8. Run MakeBranches Script on Lists of Points

Add points to groups (A, B, C, or D)

def MakeBranches ( ):

“B” 45°

“C” 40°

“D” 35°

42”

A

42”

A, B, C, or D

1. Point

Select points to start

2. Move Point

3. Create Bases

Give points a starting height

Base members created based on starting height

def ConstructMembers ( ):

4. Add Branches

Branch angle determined by input parameters From an A-point comes a B, C, and D branch

5. Cone of Intersection

Produces a cone of vision to search for intersection

6. “Snap” to Intersection

7. Recursively Build Additional Levels

When an intersection is found, two branches snap to meet and create stability

8. Recursively Build Additional Levels

Repeat steps 4-7 from endpoints of branches

Repeat steps 4-8 from endpoints of branches

Joint 2

Rail 3 Joint 2 .75” .25”

Joint 1 A0

B0

C1 A0

Rail 3

Rail 3

Joint 2 Drill Joint 2 Pocket


Branch_I.py import rhinoscriptsyntax as rs import math as math import random as random

joint3Vector = rs.VectorCreate ((0,0,2),(0,0,0)) joint4Vector = rs.VectorCreate ((0,0,3),(0,0,0)) baseJointTopVector = rs.VectorCreate ((0,0,.25),(0,0,0)) baseJointMidVector = rs.VectorCreate ((0,0,-.75),(0,0,0)) baseJointBotVector = rs.VectorCreate ((0,0,-1.75),(0,0,0))

ptATranslation = rs.VectorCreate((0,0,ptATranslationHeight),(0,0,0)) ptBTranslation = rs.VectorCreate((0,0,ptBTranslationHeight),(0,0,0))

def StartingStuff():

def randomWithinRange(min, max): randomWithinRange = min + (max - min) * random.random() return randomWithinRange randomWithinRange(0,90) #Inputs iterations = 6 baseRotation1 = 90 baseRotation2 = 210 baseRotation3 = 330 arcAngle = 30 memberAScale = 1 memberBScale = 1 memberCScale = 1 memberDScale = 1 #Lists Iterations = [] templateMember = [] branches = [] testSurfaces = [] intersectionLines = [] voidSurfaces = [] truncatedMembers = [] previousBranches = [] pointsA = [] pointsB = [] pointsC = [] pointsD = [] workingPtsA = [] workingPtsB = [] workingPtsC = [] workingPtsD = [] #Layers truncatedMembersLayer = rs.AddLayer(“Truncated Members”) connectedMembersLayer = rs.AddLayer(“Connected Members”) connectionDotLayer = rs.AddLayer(“Connection Dots”) #Vectors XAxis = rs.VectorCreate((1,0,0), (0,0,0)) YAxis = rs.VectorCreate((0,1,0), (0,0,0)) ZAxis = rs.VectorCreate((0,0,1), (0,0,0)) joint2Vector = rs.VectorCreate ((0,0,1),(0,0,0))

ptCTranslation = rs.VectorCreate((0,0,ptCTranslationHeight),(0,0,0)) voidSurfaces = rs.GetObjects(“Select Surfaces to avoid”, rs.filter.surface) #print voidSurfaces memberBase = rs.AddLine((0,0,0), (0,0,42)) rotationA = rs.GetInteger(“Specify member A’s angle”, 45, 30, 60) rotationB = rs.GetInteger(“Specify member B’s angle”, 40, 30, 60) rotationC = rs.GetInteger(“Specify member C’s angle”, 35, 30, 60) rotationD = rs.GetInteger(“Specify member D’s angle”, 30, 30, 60) memberA0 = rs.ScaleObject(memberBase, (0,0,0), (memberAScale, memberAScale, memberAScale), True) memberA = rs.RotateObject(memberA0, (0,0,0), (90-rotationA), YAxis, False) startPtA = rs.CurveStartPoint(memberA) endPtA = rs.CurveEndPoint(memberA) vectorA = rs.VectorCreate(endPtA,startPtA) memberB0 = rs.ScaleObject(memberBase, (0,0,0), (memberBScale, memberBScale, memberBScale), True) memberB = rs.RotateObject(memberB0, (0,0,0), (90-rotationB), YAxis, False) startPtB = rs.CurveStartPoint(memberB) endPtB = rs.CurveEndPoint(memberB) vectorB = rs.VectorCreate(endPtB,startPtB) memberC0 = rs.ScaleObject(memberBase, (0,0,0), (memberCScale, memberCScale, memberCScale), True) memberC = rs.RotateObject(memberC0, (0,0,0), (90-rotationC), YAxis, False) startPtC = rs.CurveStartPoint(memberC) endPtC = rs.CurveEndPoint(memberC) vectorC = rs.VectorCreate(endPtC,startPtC) memberD0 = rs.ScaleObject(memberBase, (0,0,0), (memberDScale, memberDScale, memberDScale), True) memberD = rs.RotateObject(memberD0, (0,0,0), (90-rotationD), YAxis, False) startPtD = rs.CurveStartPoint(memberD) endPtD = rs.CurveEndPoint(memberD) vectorD = rs.VectorCreate(endPtD,startPtD) PtTranslationHeightMin = math.cos(math.radians(60))*42 PtTranslationHeightMax = math.cos(math.radians(30))*42 MinHeightString = str(PtTranslationHeightMin) MaxHeightString = str(PtTranslationHeightMax) workingPtsASelect = rs.GetObjects(“Select some points to become starting points for A”,rs.filter.point) ptATranslationHeight = rs.GetReal(“Select starting height for A Points between “ + MinHeightString + “ and “ + MaxHeightString, PtTranslationHeightMin, PtTranslationHeightMin,PtTranslationHeightMax) ABaseAngle = math.degrees(math.acos(ptATranslationHeight/42)) ABaseWidth = math.sin(math.radians(ABaseAngle))*42 ABaseTranslationVector = rs.VectorCreate((ABaseWidth,0,ptATranslationHeight),(0,0,0)) workingPtsBSelect = rs.GetObjects(“Select some points to become starting points for B”,rs.filter.point) ptBTranslationHeight = rs.GetReal(“Select starting height for B Points between “ + MinHeightString + “ and “ + MaxHeightString, PtTranslationHeightMin, PtTranslationHeightMin,PtTranslationHeightMax) BBaseAngle = math.degrees(math.acos(ptBTranslationHeight/42)) BBaseWidth = math.sin(math.radians(BBaseAngle))*42 BBaseTranslationVector = rs.VectorCreate((BBaseWidth,0,ptBTranslationHeight),(0,0,0)) workingPtsCSelect = rs.GetObjects(“Select some points to become starting points for C”,rs.filter.point) ptCTranslationHeight = rs.GetReal(“Select starting height for C Points between “ + MinHeightString + “ and “ + MaxHeightString, PtTranslationHeightMin, PtTranslationHeightMin,PtTranslationHeightMax) CBaseAngle = math.degrees(math.acos(ptCTranslationHeight/42)) CBaseWidth = math.sin(math.radians(CBaseAngle))*42 CBaseTranslationVector = rs.VectorCreate((CBaseWidth,0,ptCTranslationHeight),(0,0,0)) workingPtsDSelect = rs.GetObjects(“Select some points to become starting points for D”,rs.filter.point) ptDTranslationHeight = rs.GetReal(“Select starting height for D Points between “ + MinHeightString + “ and “ + MaxHeightString, PtTranslationHeightMin, PtTranslationHeightMin,PtTranslationHeightMax) DBaseAngle = math.degrees(math.acos(ptDTranslationHeight/42)) DBaseWidth = math.sin(math.radians(DBaseAngle))*42 DBaseTranslationVector = rs.VectorCreate((DBaseWidth,0,ptDTranslationHeight),(0,0,0))

baseEndPt2 = rs.RotateObject(basePt,pt,baseRotation1 - 60, None, True) baseEndPt3 = rs.RotateObject(basePt,pt,baseRotation1 + 180, None, True) baseStartPt1 = rs.CopyObject(pt, baseJointTopVector) baseStartPt2 = rs.CopyObject(pt, baseJointMidVector) baseStartPt3 = rs.CopyObject(pt, baseJointBotVector) baseMember1 = rs.AddLine(baseStartPt1,baseEndPt1) baseMember2 = rs.AddLine(baseStartPt2,baseEndPt2) baseMember3 = rs.AddLine(baseStartPt3,baseEndPt3) rs.DeleteObject(basePt)

ptDTranslation = rs.VectorCreate((0,0,ptDTranslationHeight),(0,0,0))

if workingPtsASelect == None: None else: for ptA in workingPtsASelect: movedPtA = rs.MoveObject(ptA,ptATranslation) workingPtsA.append(movedPtA) # workingPtsA[:] = workingPtsASelect[:]

#

if workingPtsBSelect == None: None else: workingPtsB[:] = workingPtsBSelect[:] for ptB in workingPtsBSelect: movedPtB = rs.MoveObject(ptB,ptBTranslation) workingPtsB.append(movedPtB)

if workingPtsCSelect == None: None else: # workingPtsC[:] = workingPtsCSelect[:] for ptC in workingPtsCSelect: movedPtC = rs.MoveObject(ptC,ptCTranslation) workingPtsC.append(movedPtC)

#

if workingPtsDSelect == None: None else: workingPtsD[:] = workingPtsDSelect[:] for ptD in workingPtsDSelect: movedPtD = rs.MoveObject(ptD,ptDTranslation) workingPtsD.append(movedPtD) newPtsA=[] newPtsB=[] newPtsC=[] newPtsD=[] def MakeBases(): if workingPtsASelect == None: None else: for pt in workingPtsASelect: basePt = rs.CopyObject(pt,-ABaseTranslationVector) baseEndPt1 = rs.RotateObject(basePt,pt,baseRotation1 + 60, None, True) baseEndPt2 = rs.RotateObject(basePt,pt,baseRotation1 - 60, None, True) baseEndPt3 = rs.RotateObject(basePt,pt,baseRotation1 + 180, None, True) baseStartPt1 = rs.CopyObject(pt, baseJointTopVector) baseStartPt2 = rs.CopyObject(pt, baseJointMidVector) baseStartPt3 = rs.CopyObject(pt, baseJointBotVector) baseMember1 = rs.AddLine(baseStartPt1,baseEndPt1) baseMember2 = rs.AddLine(baseStartPt2,baseEndPt2) baseMember3 = rs.AddLine(baseStartPt3,baseEndPt3) rs.DeleteObject(basePt) if workingPtsBSelect == None: None else: for pt in workingPtsBSelect: basePt = rs.CopyObject(pt,-BBaseTranslationVector) baseEndPt1 = rs.RotateObject(basePt,pt,baseRotation1 + 60, None, True)

if workingPtsCSelect == None: None else: for pt in workingPtsCSelect: basePt = rs.CopyObject(pt,-CBaseTranslationVector) baseEndPt1 = rs.RotateObject(basePt,pt,baseRotation1 + 60, None, True) baseEndPt2 = rs.RotateObject(basePt,pt,baseRotation1 - 60, None, True) baseEndPt3 = rs.RotateObject(basePt,pt,baseRotation1 + 180, None, True) baseStartPt1 = rs.CopyObject(pt, baseJointTopVector) baseStartPt2 = rs.CopyObject(pt, baseJointMidVector) baseStartPt3 = rs.CopyObject(pt, baseJointBotVector) baseMember1 = rs.AddLine(baseStartPt1,baseEndPt1) baseMember2 = rs.AddLine(baseStartPt2,baseEndPt2) baseMember3 = rs.AddLine(baseStartPt3,baseEndPt3) rs.DeleteObject(basePt) if workingPtsDSelect == None: None else: for pt in workingPtsDSelect: basePt = rs.CopyObject(pt,-DBaseTranslationVector) baseEndPt1 = rs.RotateObject(basePt,pt,baseRotation1 + 60, None, True) baseEndPt2 = rs.RotateObject(basePt,pt,baseRotation1 - 60, None, True) baseEndPt3 = rs.RotateObject(basePt,pt,baseRotation1 + 180, None, True) baseStartPt1 = rs.CopyObject(pt, baseJointTopVector) baseStartPt2 = rs.CopyObject(pt, baseJointMidVector) baseStartPt3 = rs.CopyObject(pt, baseJointBotVector) baseMember1 = rs.AddLine(baseStartPt1,baseEndPt1) baseMember2 = rs.AddLine(baseStartPt2,baseEndPt2) baseMember3 = rs.AddLine(baseStartPt3,baseEndPt3) rs.DeleteObject(basePt) MakeBases() def RunStructureSystem(): #starting with an A-Branch if workingPtsA == []: None else: for point in workingPtsA: pointCOORD = rs.PointCoordinates(point) previousBranchAngle = None for previousBranch in previousBranches: previousBranchEndPt = rs.CurveEndPoint(previousBranch) previousBranchStartPt = rs.CurveStartPoint(previousBranch) if rs.Distance(previousBranchEndPt, point) > (3*rs.UnitAbsoluteTolerance()): None else: previousBranchAngleTuple = rs.Angle(previousBranchStartPt, previousBranchEndPt) previousBranchAngle = previousBranchAngleTuple[0] break #adding a B-Branch (to an A-Branch) startPoint = rs.CopyObject(point, joint2Vector) startPointCOORD = rs.PointCoordinates(startPoint) pointGUID = (rs.CopyObject(startPoint,vectorB)) point2 = rs.PointCoordinates(pointGUID) rs.DeleteObject(pointGUID)

newLine = rs.AddLine(startPointCOORD,point2) if previousBranchAngle == None: rotationTestTuple = divmod(len(Iterations)+2, 2) rotationTest = rotationTestTuple[1] if rotationTest == 0: newLineRotated = rs.RotateObject(newLine, startPointCOORD, baseRotation1, ZAxis, False) else: newLineRotated = rs.RotateObject(newLine, startPointCOORD, baseRotation1+180, ZAxis, False) else: newLineRotated = rs.RotateObject(newLine, startPointCOORD, previousBranchAngle+300, ZAxis, False) rotatedPoint = rs.CurveEndPoint(newLineRotated) for srf in voidSurfaces: voidSurfaceIntersection = rs.CurveSurfaceIntersection(newLineRotated, srf) if len(voidSurfaceIntersection) == 0 and voidSurfaces.index(srf)+1 < len(voidSurfaces): None elif len(voidSurfaceIntersection) == 0 and voidSurfaces.index(srf)+1 == len(voidSurfaces): memberLength = rs.CurveLength(newLineRotated) memberStartPt = rs.CurveStartPoint(newLineRotated) memberEndPt = rs.CurveEndPoint(newLineRotated) memberRotate1 = rs.RotateObject(newLineRotated, memberStartPt, arcAngle, None, True) memberRotate2 = rs.RotateObject(newLineRotated, memberStartPt, -arcAngle, None, True) memberRotate1EndPt = rs.CurveEndPoint(memberRotate1) memberRotate2EndPt = rs.CurveEndPoint(memberRotate2) testArc = rs.AddArc3Pt(memberRotate1EndPt, memberRotate2EndPt, memberEndPt) testArcSrf = rs.AddRevSrf(testArc, newLineRotated, 0, 360) testArcSrfBorder = rs.DuplicateSurfaceBorder(testArcSrf) testArcSrfBorderPlane = rs.AddPlanarSrf(testArcSrfBorder[0]) memberSphere = rs.AddSphere(memberStartPt, memberLength) testArcSurfaceTuple = rs.SplitBrep(memberSphere, testArcSrfBorderPlane, True) testArcSurfaceTuple0 = rs.SurfaceArea(testArcSurfaceTuple[0]) testArcSurfaceTuple1 = rs.SurfaceArea(testArcSurfaceTuple[1]) if testArcSurfaceTuple0 < testArcSurfaceTuple1: testArcSurface = testArcSurfaceTuple[0] rs.DeleteObjects((testArcSurfaceTuple[1], testArcSrf, testArcSrfBorder[0], testArcSrfBorder[1], testArcSrfBorderPlane)) else: testArcSurface = testArcSurfaceTuple[1] rs.DeleteObjects((testArcSurfaceTuple[0], testArcSrf, testArcSrfBorder[0], testArcSrfBorder[1], testArcSrfBorderPlane)) rs.DeleteObjects((memberRotate1, memberRotate2)) rs.DeleteObject(testArc) if len(testSurfaces) > 0: for j in testSurfaces: intersectionLine = rs.IntersectBreps(j, testArcSurface) if intersectionLine == [] and testSurfaces.index(j)+1 < len(testSurfaces): None elif intersectionLine == [] and testSurfaces.index(j)+1 == len(testSurfaces): testSurfaces.append(testArcSurface) branches.append(newLineRotated) newPtsB.append(rs.AddPoint(rotatedPoint)) break else: testSurfaceAreaCentroid = rs.SurfaceAreaCentroid(j) sacPt = rs.AddPoint(testSurfaceAreaCentroid[0]) scp = rs.BrepClosestPoint(j,sacPt) sacPtFinal = rs.AddPoint(scp[0]) intersectionLineMid = rs.CurveMidPoint(intersectionLine) intersectionLineMidPt = rs.AddPoint(intersectionLineMid) rotationPt = intersectionLineMidPt rs.DeleteObject(newLineRotated) newLineRotated = rs.AddLine(startPointCOORD,rotationPt) rotatedPoint = rs.CurveEndPoint(newLineRotated) connectionDot = rs.AddTextDot(“intersection”,rotationPt) testSurfaces.remove(j) rs.DeleteObjects((j, testArcSurface, intersectionLine, sacPt)) rs.ObjectLayer(newLineRotated, connectedMembersLayer) rs.ObjectLayer(connectionDot, connectionDotLayer) for branch in branches: if rs.Distance(rs.CurveEndPoint(branch),sacPtFinal) < (10*rs.UnitAbsoluteTolerance()): newBranch = rs.AddLine(rs.CurveStartPoint(branch), rotationPt) branches.remove(branch) rs.DeleteObject(branch)

A small sample of the 2000+ line final script.


2. Select Areas to Avoid

1. Starting Ground

Select a surface as a ground condition

3. Select Paths

Select Designated Areas where voids are desired

4. Construct Field of Points

Select curves that represent circulation routes

6. Move Points

5. Remove Points

A grid of starting points are set up based on U and V spacing

7. Give points a starting identity

Move points away from paths based on a factor of the inverse of distance from the two nearest paths

Delete points from areas designated to avoid

8. Run MakeBranches Script on Lists of Points

Add points to groups (A, B, C, or D)

def MakeBranches ( ):

“B” 45°

“C” 40°

“D” 35°

42”

A

42”

A, B, C, or D

1. Point

2. Move Point

Select points to start

3. Create Bases

Give points a starting height

4. Add Branches

Base members created based on starting height

6. “Snap” to Intersection

5. Cone of Intersection

Branch angle determined by input parameters From an A-point comes a B, C, and D branch

7. Recursively Build Additional Levels

When an intersection is found, two branches snap to meet and create stability

Produces a cone of vision to search for intersection

def ConstructMembers ( ):

8. Recursively Build Additional Levels

Repeat steps 4-7 from endpoints of branches

Repeat steps 4-8 from endpoints of branches

Joint 2

Rail 3 Joint 2 .75” .25”

Joint 1

B0 C1

A3 C2

B2

Rail 2

Rail 2

A3 A4

9. Joint 2 Flat Triangle 10. Offset Triangle 11. Joint 2 Surfaces

B2

Rail 2

B5

3. Offset Triangle

Joint 1

Joint 2 Pocket

C1 A0

A0

.75” .25” .75” .25” .75”

B0

Joint 2 Drill

Rail 3

Rail 3

Edge 2

4. Joint 1 Top Surface 5. Joint 1 Bottom Surface 6. Joint 1 Face Surfaces Rail 1

Rail 1

Edge 1

Edge 3

Joint 1 Drill

Rail 1

1. Existing Line From def Make Branches

2. Joint 1 Triangle

7. Middle Loft Rail

B, C, D

C D A

BC D

Script Taxonomy A

B

8. Joint 2 Triangle

Variable edge length determines the member’s thickness

C, D, A

C

D, A, B

D

A, B, C

Starting Point A

B

DA B

12. Loft Surface 1

From edge of joint 1 face surface through the middle loft triangle to the edge of joint 2 surface

AB C

C

D

Intersecting Members

A

C

B

A

D

B

D

C

C

A

D B

45°

A

B

C

40°

35°

30°

D

Member

Degree (rotated from vertical)

Truncated Members

13. Loft Surface 2

14. Loft Surface 3

15. Edge Surface 4

Create surface from 3 naked edges

16. Drill Lines / Pocket Lines

For members that continue growth on joint 2, 3/8” drill, for intersecting members, 1/4” drill, otherwise no drill


Construct Members_I.py import rhinoscriptsyntax as rs import math as math import random as random from System.Drawing import Color

stockPt2B = rs.AddPoint(1.75,45,1.8) stockPt3B = rs.AddPoint(.75,45,1.8) stockPt1C = rs.AddPoint(1.85,3,1.7) stockPt2C = rs.AddPoint(1.75,45,1.7) stockPt3C = rs.AddPoint(.75,45,1.75) rs.ObjectLayer((stock), stocksLayer) rs.ObjectLayer(stockPt1, stocksLayer) rs.ObjectLayer(stockPt2, stocksLayer) rs.ObjectLayer(stockPt3, stocksLayer)

else: None for z in deltaZTestList: if z > 0: break elif z < 0 and deltaZTestList.index(z)+1 < len(deltaZTestList): None else: topLowestMembers.append(a) lowestMembers.remove(a) break findLowestMembers()

XAxis = rs.VectorCreate((1,0,0), (0,0,0))

def findBaseMembers(): def findBotMembers():

allMembers = [] topMembers = [] midMembers = [] botMembers = [] intMembers = [] intMembersTop = [] intMembersBot = [] baseMembers = [] lowestMembers = [] topLowestMembers = [] bottomBaseMembers = [] orientListLength = [] groupedMembers = []

for i in allMembers: deltaZ = rs.Angle((rs.CurveStartPoint(i)), (rs.CurveEndPoint(i))) if deltaZ[4] < 0: baseMembers.append(i) else: None for a in baseMembers: deltaZBaseTestList = [] for b in baseMembers: if (3*rs.UnitAbsoluteTolerance()) < rs.Distance((rs.CurveStartPoint(a)), (rs.CurveStartPoint(b))) < (1+3*rs.UnitAbsoluteTolerance()): testBaseLine = rs.AddLine((rs.CurveStartPoint(a)), (rs.CurveStartPoint(b))) deltaZBaseTestLineTuple = rs.Angle((rs.CurveStartPoint(testBaseLine)), (rs.CurveEndPoint(testBaseLine))) deltaZBaseTestLine = deltaZBaseTestLineTuple[4] deltaZBaseTestList.append(deltaZBaseTestLine) rs.DeleteObject(testBaseLine) else: None for z in deltaZBaseTestList: if z < 0: break elif z > 0 and deltaZBaseTestList.index(z)+1 < len(deltaZBaseTestList): None else: bottomBaseMembers.append(a) baseMembers.remove(a) break findBaseMembers()

drillLinesLayer = rs.AddLayer(“Drill Lines”, Color.Green) memberSurfacesLayer = rs.AddLayer(“Member Surfaces”, Color.Lavender) stocksLayer = rs.AddLayer(“Stock”, Color.Black) labelsLayer = rs.AddLayer(“Labels”, Color.Aquamarine) booleanItems = (“Hmmm”, “No”, “Yes”), (“AreYouSure”, “No”, “Yes”) orientBooleanTuple = rs.GetBoolean(“Do you want to lay out the members in stock?”, booleanItems, (False, True)) orientBoolean = orientBooleanTuple[0] members = rs.GetObjects(“Select curves to become members”, rs.filter.curve) allMembers[:] = members[:] #Variable (actual diameter is slightly less. An input of 1.75 yields 1.51 output): globalMemberDiameter = 1.85 baseGlobalMemberDiameter = 2 stockRec = rs.AddRectangle((rs.WorldXYPlane()), 4, 48) stockCopy = rs.CopyObject(stockRec, (0,0,3.5)) stock = rs.ExplodeCurves(stockRec, True) #stock = rs.AddBox(((0,0,0),(4,0,0),(4,48,0),(0,48,0), (0,0,3.5), (4,0,3.5), (4,48,3.5), (0,48,3.5))) stockPt1 = rs.AddPoint(2,3,1.8) stockPt2 = rs.AddPoint(1.5,45,1.8) stockPt3 = rs.AddPoint(.5,45,1.8) stockPt1B = rs.AddPoint(1.75,3,1.8)

for i in allMembers: for j in allMembers: if rs.Distance(rs.CurveEndPoint(j), (rs.CurveStartPoint(i))) < (1+3*rs.UnitAbsoluteTolerance()): botMembers.append(i) else: None

jCopyAngle = jCopyAngleTuple[0] splitAngleEndPt = rs.CopyObject(intersectionPt, splitVector) splitAngleTuple = rs.Angle(intersectionPt, splitAngleEndPt, angleCalcPlane) splitAngle = splitAngleTuple[0] rs.DeleteObjects((intersectionPt, iCopy, jCopy, splitAngleEndPt)) if j != i and rs.Distance(rs.CurveEndPoint(j), rs.CurveEndPoint(i)) < (3*rs.UnitAbsoluteTolerance()): if jCopyAngle > 0: intMembersTop.append(i) intMembersBot.append(j) else: intMembersTop.append(j) intMembersBot.append(i) break else: None else: None findIntMembers()

findBotMembers() def findMidMembers(): for i in allMembers: for j in allMembers: if (2-3*rs.UnitAbsoluteTolerance()) < rs.Distance(rs.CurveEndPoint(j), (rs.CurveStartPoint(i))) < (2+3*rs.UnitAbsoluteTolerance()): midMembers.append(i) else: None findMidMembers() def findTopMembers(): for i in allMembers: for j in allMembers: if (3-3*rs.UnitAbsoluteTolerance()) < rs.Distance(rs.CurveEndPoint(j), (rs.CurveStartPoint(i))) < (3+3*rs.UnitAbsoluteTolerance()): topMembers.append(i) else: None

def constructBotMember():

memberDiameter = globalMemberDiameter firstTriangleLine1 = rs.AddLine((0,0,0), ((memberDiameter),0,0)) firstTriangleLine1Ro = rs.RotateObject(firstTriangleLine1, (0,0,0), -60) firstTriangleLine1RoStPt = rs.CurveStartPoint(firstTriangleLine1Ro) firstTriangleLine1RoEndPt = rs.CurveEndPoint(firstTriangleLine1Ro) firstTriangleLine1RoVector = rs.VectorCreate(firstTriangleLine1RoEndPt, firstTriangleLine1RoStPt) firstTriangleLine2 = rs.CopyObject(firstTriangleLine1Ro, firstTriangleLine1RoVector) firstTriangleLine2Ro = rs.RotateObject(firstTriangleLine2, firstTriangleLine1RoEndPt, 120) firstTriangleLine2RoEndPt = rs.CurveEndPoint(firstTriangleLine2Ro) firstTriangleLine3 = rs.AddLine(firstTriangleLine2RoEndPt, firstTriangleLine1RoStPt) firstTriangle = rs.JoinCurves((firstTriangleLine1Ro, firstTriangleLine2Ro, firstTriangleLine3), True) firstTriangleCentroid = rs.CurveAreaCentroid(firstTriangle) firstTriangleCentroidPt = rs.AddPoint(firstTriangleCentroid[0]) firstTriangleCentroidVector = rs.VectorCreate((0,0,0),(0,0,6)) firstTriangleCentroidMoved = rs.CopyObject(firstTriangleCentroidPt, firstTriangleCentroidVector)

findTopMembers() def findLowestMembers(): for i in allMembers: for j in baseMembers: if (2.75-3*rs.UnitAbsoluteTolerance()) < rs.Distance((rs.CurveStartPoint(i)), (rs.CurveStartPoint(j))) < (4.75+3*rs.UnitAbsoluteTolerance()): lowestMembers.append(i) break else: None for k in bottomBaseMembers: if (2.75-3*rs.UnitAbsoluteTolerance()) < rs.Distance((rs.CurveStartPoint(i)), (rs.CurveStartPoint(k))) < (2.75+3*rs.UnitAbsoluteTolerance()): lowestMembers.append(i) break else: None for a in lowestMembers: deltaZTestList = [] for b in lowestMembers: if (3*rs.UnitAbsoluteTolerance()) < rs.Distance((rs.CurveStartPoint(a)), (rs.CurveStartPoint(b))) < (1+3*rs.UnitAbsoluteTolerance()): testLine = rs.AddLine((rs.CurveStartPoint(a)), (rs.CurveStartPoint(b))) deltaZTestLineTuple = rs.Angle((rs.CurveStartPoint(testLine)), (rs.CurveEndPoint(testLine))) deltaZTestLine = deltaZTestLineTuple[4] deltaZTestList.append(deltaZTestLine) rs.DeleteObject(testLine)

def findIntMembers(): for i in allMembers: for j in allMembers: if rs.Distance(rs.CurveEndPoint(j), rs.CurveEndPoint(i)) < (3*rs.UnitAbsoluteTolerance()): intMembers.append(i) for i in intMembers: if intMembersTop.count(i) == 0 and intMembersBot.count(i) == 0: for j in intMembers: iCopy = rs.CopyObject(i) jCopy = rs.CopyObject(j) rs.ReverseCurve(jCopy) rs.ReverseCurve(iCopy) intersectionPt = rs.AddPoint(rs.CurveStartPoint(iCopy)) iCopyVector = rs.VectorCreate((rs.CurveEndPoint(iCopy)), (rs.CurveStartPoint(iCopy))) jCopyVector = rs.VectorCreate((rs.CurveEndPoint(jCopy)), (rs.CurveStartPoint(jCopy))) splitVector = rs.VectorAdd(iCopyVector, jCopyVector) angleCalcPlane = rs.PlaneFromNormal(intersectionPt, (0,0,1), splitVector) iCopyAngleTuple = rs.Angle((rs.CurveStartPoint(iCopy)), (rs.CurveEndPoint(iCopy)), angleCalcPlane) iCopyAngle = iCopyAngleTuple[0] jCopyAngleTuple = rs.Angle((rs.CurveStartPoint(jCopy)), (rs.CurveEndPoint(jCopy)), angleCalcPlane)

secondTriangle = rs.RotateObject(firstTriangle, firstTriangleCentroidPt, -60, None, True) secondTriangleCentroid = rs.CurveAreaCentroid(secondTriangle) secondTriangleCentroidPt = rs.AddPoint(secondTriangleCentroid[0]) secondTriangleCentroidVector = rs.VectorCreate((0,0,6),(0,0,0)) secondTriangleCentroidMoved = rs.CopyObject(secondTriangleCentroidPt, secondTriangleCentroidVector) #Creating Joint1: joint1Triangle1Line1 = rs.AddLine((0,0,0), (-3,0,0)) joint1Triangle1Vector = rs.VectorCreate((-3,0,0), (0,0,0)) joint1Triangle1Line2 = rs.CopyObject(joint1Triangle1Line1, joint1Triangle1Vector) joint1Triangle1Line2Ro = rs.RotateObject(joint1Triangle1Line2, (-3,0,0), 120) joint1Triangle1Line2StPt = rs.CurveStartPoint(joint1Triangle1Line2Ro) joint1Triangle1Line2EndPt = rs.CurveEndPoint(joint1Triangle1Line2Ro) joint1Triangle1Line2RoVector = rs.VectorCreate(joint1Triangle1Line2EndPt, joint1Triangle1Line2StPt) joint1Triangle1Line3 = rs.CopyObject(joint1Triangle1Line2Ro, joint1Triangle1Line2RoVector) joint1Triangle1Line3Ro = rs.RotateObject(joint1Triangle1Line3, joint1Triangle1Line2EndPt, 120) joint1Triangle1 = rs.JoinCurves((joint1Triangle1Line1, joint1Triangle1Line2Ro, joint1Triangle1Line3Ro), True) joint1Triangle1Centroid = rs.CurveAreaCentroid(joint1Triangle1) joint1Triangle1CentroidPt = rs.AddPoint(joint1Triangle1Centroid[0]) joint1Triangle0 = rs.CopyObject(joint1Triangle1, (0,0,1)) joint1Triangle2 = rs.CopyObject(joint1Triangle1, (0,0,-1)) joint1Triangle3 = rs.CopyObject(joint1Triangle1, (0,0,-2))



output


On-Site Iterations

A

B

C

Stage I - Growth Point Placement / Surface Shape / Base Rotation

Variables Growth Points: A / B / C / D Growth Point Height: 22” - 36” Base Rotation: 0° / 30° / 60° Vertical Member Angles: 30° - 60° Intersection Arc Angle: 0° - 30° Surfaces to Avoid: Select Surfaces

Stage II - Growth Point Configurations Stage III -variations Growth Point Height Membersite AngleinVariation Iterations of the final script, tested in numerous in its/ Vertical eventual Liberty Lofts, downtown Ann Arbor, Michigan. Blue surfaces represent the “invisible surfaces”4that 1 (Variation) 2 (Variation) (Variation) restricted the growth of the system as the script generated an output.

1 A

2

3

B 5 (Variation)

4

5

6

7

8

C

9 (Variation) 9

7 (Variation)

8 (Variation)


On-Site Iterations

A

B

C

Stage I - Growth Point Placement / Surface Shape / Base Rotation

Variables Growth Points: A / B / C / D Growth Point Height: 22” - 36” Base Rotation: 0° / 30° / 60° Vertical Member Angles: 30° - 60° Intersection Arc Angle: 0° - 30° Surfaces to Avoid: Select Surfaces

Stage II - Growth Point Configurations Stage III - Growth Point Height / Vertical Member Angle Variation

1 A

2

1 (Variation)

2 (Variation)

4 (Variation)

5 (Variation)

7 (Variation)

8 (Variation)

3

B

4

5

6

7

8

C

9 (Variation) 9 D

Stage V -Final Form Stage IV - Growth Point Height / Placement Final Adjustment

1 (Final Variation)

2 (Final Variations)

7 (Final Variations)


ons)

9 (Variation)

Stage V -Fin Stage IV - Growth Point Height / Placement Final Adjustment

1 (Final Variation)

2 (Final Variations)

Stage V -Final Form

7 (Final Variations)


77 81

2

66

17

33

4176

14

47

Lower surface to avoid

65

11

67

80

55 28

15

39

28

51

56

64

69

8

36

64

35

69

26

61 1-B

2-B

3-B

4-B 5-B-Int 6-B-Int 7-B

33

74

8-B

9-B

10-B

11-B

12-B

13-B

14-B 15-B-Int 16-B-Int 17-B 18-B-Int 19-B-Int 20-M 21-M

22-M 23-M

24-M

25-M

26-M

27-M

28-M

29

48-T 49-T-Int 50-T-Int 51-T

52-T

53-T

54-T

55-T

56

2

60 67

Final Joint Details 21

28

Lower surface to avoid 26

6-M

27-M

28-M

29-M 30-M

3-T

54-T

55-T

56-T

31-M

Upper surface to avoid 32-M

33-M 34-M 35-M 36-M-Int 37-M-Int 38-M-Int 39-T -Int 40-T-Int 41-T-Int 42-T-Int 43-T 44-T

45-T

46-T

47-T

57-T 58-Base 59-Base 60-Base 61-Base 62-Base 63-Base 64-Base 65-Base 66-Base 67-Base 68-Base 69-Base 70-Low 71-Low 72-Low 73-low 74-Low 75-Low 76-Low 77-Low 78-Low 79-Low 80-Low 81-Low

3/8� Hex Bolt


Elevation

Plan Upper surface to avoid

Wall to avoid

24

46

45

5

6 23

4

Wall to avoid

8

50

49

28

26

51

38

25 57

Wall to avoid

10

22

7

47

48

11

27

17

41

9

36 2

44 31

27 33

21

19

43

39

40 16

37 1

33 56

12

13

20

29

30

15

55

32

53 14

80 74

75

72

35

71

78

77

70

Pathway

73

81 76 Lower surface to avoid

63

62 68

61

60 67

58

59 66

65

64

69

Working drawings of the final output, a culmination of joint/branch development and script, to be installed in Liberty Lofts, downtown Ann Arbor. The final form contained 81 unique members that were cut on the 5-axis CNC router and assembled on site.


Plan Wall to avoid

24

13

5

Pathway

27 48

46 9

59 45

27

63 Wall to avoid

58

6

62

66

17

68 2

33

31

39

28

51

15

36 35

11

75

61 33

74

2

60 67

80 avoid

56 14

55

47

2

64

69

41

44

32

65

23

ll to avoid

21

28 8

Lower surface to avoid 26

Upper surface to avoid


1-B

2-B

3-B

4-B 5-B-Int 6-B-Int 7-B

8-B

9-B

10-B

11-B

12-B

13-B

14-B 15-B-Int 16-B-Int 17-B 18-B-Int 19-B-Int 20-M 21-M

22-M 23-M

24-M

25-M

26-M

27-M

28-M

29-M 30-M

31-M

32-M

33-M 34-M 35-M 36-M-Int 37-M-Int 38-M-Int 39-T

Final Joint Details

Standard Connection

Typical Cut Procedure 3/4” 3-Flute Rougher—Swarf Cut 3/8” Rougher—Pocket Operation

Example Assembly Detail

3/8” Drill


27-M

28-M

29-M 30-M

31-M

32-M

33-M 34-M 35-M 36-M-Int 37-M-Int 38-M-Int 39-T -Int 40-T-Int 41-T-Int 42-T-Int 43-T 44-T

45-T

46-T

47-T

48-T 49-T-Int 50-T-Int 51-T

52-T

53-T

54-T

55-T

56-T

57-T 58-Base 59-Base 60-Base 61-Base 62-Base 63-Base 64-Base 65-Base 66-Base 67-Base 68-Base 69-Base 70-Low 71-Low 72-Low 73-low 74-Low 75-Low 76-Low 77-Low 78-Low 79-Low 80-Low 81-Low

1/4” Hex Bolt

3/8” Hex Bolt

Standard Connection

Typical Cut Procedure 3/4” 3-Flute Rougher—Swarf Cut 3/8” Rougher—Pocket Operation 3/8” Drill

“Snapped” Connection

Base Connection



production + assembly










Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.