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â&#x20AC;&#x2122;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 â&#x20AC;&#x153;objectileâ&#x20AC;?. 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 â&#x20AC;&#x153;branchesâ&#x20AC;? 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â&#x20AC;? 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