说明
主要学习内容
- Learn when and how to Use Python in Dynamo
- Learn C# basics and how to use the Revit API in Dynamo
- Learn how to build your own zero-touch, read-only nodes using C#
- Learn how to control and manipulate the Dynamo UI and interactions using Extensions
讲师
- Thomas MahonFounding Director of Bimorph Consultancy, Software Engineer and computational design/BIM specialist. Creator of bimorphNodes. Authorized Autodesk Developer. Bimorph is a digital engineering firm transforming the way Architects, Engineers and Building Contractors realise buildings
- RWRacel WilliamsRacel Williams is an AI Development Manager for the Building, Infrastructure, and Design Group. She has a B.S. in Marketing from the University of Florida and Master’s degrees in Architecture and Human-Computer Interaction from Georgia Tech where her research focus was Augmented Reality and Tangible Interaction. In 2013, she joined Autodesk as an intern where she developed a mobile AR prototype for in-situ annotation and visualization. After becoming full-time, she went on to become the UX Designer for FormIt, Dynamo, and other related projects. Later, she became the Product Owner of Dynamo and led the development team in shipping multiple versions of Dynamo. She has given numerous talks and workshops on Dynamo around the world. Currently, she is now helping Autodesk shape how the company will integrate AI and Machine Learning in AEC workflows by leading a team of ML researchers and engineers to build the next generation of AEC tools.
PRESENTER: I think we have everyone, so I'm going to ask you guys to quiet down, so we can get cracking. All right, something weird is going on with my laptop, but bear with me. Hopefully this works, and it stops playing by itself. Cool, so hopefully-- yeah. Anyone know how to work PowerPoint. It's playing by itself. I don't know why. [LAUGHS] No. OK. It's just advancing by itself.
AUDIENCE: [INAUDIBLE]
PRESENTER: No. I don't know. Let's see. I'm just going to keep flicking back and forth if it keeps doing it. Cool, so-- sorry?
AUDIENCE: [INAUDIBLE]
PRESENTER: Transitions on mouse click.
AUDIENCE: [INAUDIBLE]
PRESENTER: Yeah, no. It's OK. We can-- I think it's fine now. All right, so what we're going to do in this session, we've looked at Python previously. So you saw how to develop directly into Dynamo, which is pretty cool because you get immediate feedback. And hopefully by the end of the session, you will understand the value of that.
In this session, we're going to go back right back to basics and learn a bit about programming languages in general, about compilers. Not too much. Don't worry. And then we're going to learn the basics of C #, which is a different programming language than Python, but it's also the language that Revit and Dynamo were written in. So it's going to provide a little bit of a different way to integrate with those two.
So this is what I get asked the most probably, like should I learn Python or C #? There is no right or wrong answer by the way. Everyone's going to give you their own opinion. The answer is basically depends what you want to do, how much time do, you have what do you want to accomplish. So by giving you guys a broad overview of all of them, hopefully you can pick for yourselves and see which one is more suited. What I will say about the C # side, hopefully you'll see, it's a little bit friendlier to beginners. And it gives you more assistance along the way so less of stabbing in the dark, I guess.
I'm going to have to advance with this. So how-- backing up, we have code. We were writing letters into a little gray box and then something was happening on the screen, something was executing. So I'd like to pause for a second and just go through the journey of like what happens when we go from that source code that we wrote, the little text that we typed in, all the way to the machine executing those things. How do we get from one to the other, which will help us understand the language a little bit better.
So we generally start of on the right hand side with high level code. So this is, for example, it could be Python, it could be JavaScript or C. It's a high level language. So you type in things that resemble to English, and you as a human can read it. What happens is this needs to be translated into something that machines can understand. So there's several steps for that. You can go to assembly code first, and then eventually what actually needs to happen is it needs to be translated to machine code on the left. So imagine having to write your Python scripts like the thing on the left. That's what they used to do in the 60s. People did that. It was very hard. So we have it very lucky today that we can do that.
So to get from one to the other, what happens is it goes through a process usually called compilation. So we start off with source code. So for example print 4 times a variable plus 1. First thing that happens is a lexer takes this text because it's just a text file. And it starts making a list, and breaking it down into its component. So it identifies oh, the first thing is print. Then I have an operation, which is the semicolon, and then I have a number, and just builds up the list of these things and recognizes, which part of the text is what.
The next step that happens after this is that list gets basically transformed by a parser into something called an abstract syntax tree. You'll hear this term in Dynamo land, for example, when you're dealing with UI nodes. Under the hood, Dynamo is doing this and compiling your stuff to something called DesignScript.
So it builds an abstract syntax tree from your graph, and it basically makes this diagram of like, OK, this calls this. And then this depends on that. And it will use this abstract syntax tree to then build something called an action tree, which is a kind of a more developed version of that. And eventually this then gets transformed into byte code and run on the machine.
Now this might look familiar to you. If you look at the diagram on the left, and we kind of flipped the Dynamo graph on its head, it's exactly the same thing. So when you're programming visually, you're really just writing an abstract syntax tree at a 90 degree angle kind of thing. So this is why it feels intuitive. It's because we can visually make these things, and it's a lot easier than having to type the code in and imagine in your mind actually these two things depend on that. So that's where the intuitive of visual programming comes from.
So back to our question, how does help us figure out how to go from source code to machine code? And that is the job of something called a compiler, essentially. There's a joke in here. So if you ever see programmers slacking off, it's usually because it's compiling. Computers are usually fast enough now that it's no longer a valid excuse. But I wanted to touch on a different-- since we're talking about Python earlier and we're going to be talking about C # in the second, I wanted to touch a bit about on the different kind of compilers or flavors of these steps, if you will.
So traditionally, you can have a compiler or an interpreter. And you'll hear these terms when we talk about different languages. I'm going to go through the differences between them. So a compiler takes your entire program, for example, analyzes all of it, and then spits out machine code. An interpreter goes here's the first line, I'm going to read it, process it, and execute it. Then I'm going to go to line two. So it's very sequential. A compiler kind of generates this kind of intermediate object code, whereas an interpreter usually does it and it just straight up executes things.
A compiler executes faster because it knows about the entire program, and it can do optimizations, and it can do all sorts of other things. Whereas an interpreter is just going in the dark and saying, oh, here's the next step, here's the next step. And it doesn't know what comes next. So we can't do a lot of these optimizations. A compiler, however, requires more memory because it has to keep the entire program into memory when it compiles it, and that kind of has a knock on effect. An interpreter is faster because it just goes line by line, so you only ever need to know about the line that you're currently on.
A compiler doesn't compile every time you run. So if I take my code, and I compile it, when I go to run it, I never need to compile it again. It just runs. If I run it a million times, it just runs. An interpreter, however, if you run it a million times, it needs to basically do this compilation a million times. And in terms of errors. If you're dealing with a compiler this will give you a lot of errors at compile time, so when you're trying to compile. Whereas an interpreter because it doesn't know what the next line is it will only display the error when it's running your code. So that means that you don't know what you're doing wrong until you actually run your code.
So examples of compiled versus interpreted languages, and why this is relevant for us is C#, Java, C++ and a lot of others are compiled languages. We type code, a compiler does a lot of heavy lifting, and it spits out an object, a DLL usually or something like that. Python, JavaScript, and a few others are interpreted languages. So like we said, they go line by line, meaning that they get compiled every time, and there's performance drawbacks there. But there is also kind of ease of use in that approach.
I've put C # in this pile as well because, as you'll see C # is a bit of a-- and Java different kinds. They're kind of hybrid between the two where basically it's got a compile stage, so it compiles your program to something called an intermediate language representation. And then when it runs that code , it further does interpretation on that to optimize it based on the machine that it's running. So it's kind of like a two stage, and it tries to get the best of both worlds, which is why it's a pretty cool language. And it's generally regarded as a next generation kind of compiler.
So that's it for the intro. Any questions on that before I go on? No burning questions. Curiosities? No, OK? Got one.
AUDIENCE: [INAUDIBLE]
PRESENTER: Well we had them up on the screen earlier. So you pick the ones you want from the left or the right. That's hard to say. I stick with C# so. Because it gives you-- I think it's the analysis of your entire program and it gives you all the errors it finds when it tries to compile. That is massively helpful, for example. So I know that I don't have any errors in the codes before I run it. And if there are any errors, it's because I'm stupid, not the computer. So it kind of helps kind of get rid of some errors plus it actually runs a lot faster.
So object oriented programming.
Yeah
AUDIENCE: [INAUDIBLE]
PRESENTER: Pardon.
AUDIENCE: [INAUDIBLE]
PRESENTER: Yeah, so that's the part with interpreted languages. I don't need to have a massive compiler, write a lot of code, fix all the errors. I can just type three lines and it runs, right? So you can prototype in interpreted languages much, much faster. So that's why I said you, pick what you need based on what you're doing.
So object oriented programming because we're going to need to know these concepts for the C # bits. It's called object oriented for a very simple reason. It looks at the world through the lens of objects. Like everything in the world is an object. I'm an object. The table's an object, but so are actions. So if I'm performing a particular action, I can model that as an object in object oriented programming.
So objects in this world have two things they have data, which are usually called properties, things like color name height, whatever. And they have methods, which ability to do other stuff. So I can move. I can scale. I can talk. I can do stuff. So think about it as data is I have something, and then methods are I can do something.
So a little terminology. Objects like words like we saw are bits of data and methods stuck together. So a particular object has some properties, and it knows how to do some stuff. Objects also have a type. So you identify as a type. So for example I'm a human type. The desk is a type of furniture, and so on. So they function on this idea of something having a type and discriminating objects based on that.
Classes, and we'll come to those in a second, they're basically a way to define types, custom type. So Tom told you earlier that Boolean is a type. It's a true or false basic, right? So that's an example of a type. Integer, double string, they're are all types. So they all come predefined with the language. However, with an object oriented language, you can define your own custom types, and you do that through the use of classes.
An instance is basically one particular-- I'm not sure if there is a better word for it, instance of a type. So if I'm an instance of the type human, I'm a particular instance. I am called Radu, and I'm unique. So are all of you. Right so I represent a type, but I also have my own properties that no one else has. There might be other people with the same name, but we all have different properties. So instance, is something you can point to and say, yep, that's of that type, and it's that particular instance. And you identify objects like this.
And then something called static is a concept where you no longer have something that can have multiple instances, but instead you have a class that can only have one. So an example of this would be from The Matrix. There can only be one. He is the chosen one. He is a static class. We'll see another example.
So in an applied world, like if we looked at the this through the lens of architecture, for example, let's consider a truss for example right. A truss is defined basically by a list of points. Then the capability to generate geometry. So we have a list of top points, a list of bottom points for our truss. And then we have a method to generate that geometry and out comes an actual truss, right?
So in this case, we can say that the class truss is basically a type of geometry, and it has some properties and capabilities whenever we make a new truss, we say we make an instance of that class. So if we make seven trusses, they can all be different instances and they are unique in their own ways. But they also share the same capabilities that the base truss class has.
So how does that relate to Dynamo? For example, if you take a list of inputs, a list of nodes, pairs of points and things like that, and you feed that to the method that generates geometry, it could spit out for example truss instances. So whenever you're making a wall and you feed it some inputs, what that method is actually doing is creating new instances of that class, right? So the method that Tom used earlier wall.create, that is a method that creates a new instance of the class wall, or it tells Revit to do it for you, essentially, if we are kind of getting into the nitty gritty of it.
So that's it for object oriented programming. I'd like to ask if there's any questions before we get to C#, and I promise there's only five more minutes of lecture and then we actually type stuff. No? Can I go on? OK. So this should feel familiar because it's very, very close to Python. The reason it's close to Python in terms of syntax is because most languages are close to a language called C. So they all kind of look familiar, which is why it sometimes is confusing.
But there is a couple of base types built into a C #. There is an integer type, for example. And you declare these things by typing the type first, so int for example. I have a variable named x, and I'm assigning it the value 5 here. So integers are whole numbers just like Tom told you. Doubles are numbers with decimal points. Strings are basically representations of text. So if I say hello world, that's a text, which means in computer language it's a string. And booleans are just true or false. They can never be anything else. The beauty with booleans is it's either true or false. It can be undefined, for example. No, it's true or false, and computers like that. They don't like uncertainty.
So how do you write these things? In C #, you write statements. So like I said at the beginning, to declare a variable, for example, you declare its type, its name. So I say int x or I can go int y And then I assign a value to it, and then I type out the value. More importantly in C #, you always finish your statement by pulling semicolon at the end. If you don't horrible, things will happen. It's not like in Python where you can go around the place and not put any semicolons. There is structure here. I'm kidding. Not horrible things will happen. It just won't compile.
So how do we-- we saw how we define a variable. So let's look at how we define a method now, and then we're going to jump straight into coding a little bit. When we define methods, there's a couple of things we'd need to define about that method before we actually write the code of that method. We need to declare something called an axis modifier, which simply says who can see this method. If it's public, anyone can see it. If it's private, only the class it's part of can see it. Then you have a modifier, which you can omit, as in not have. So if you want to make it static, you type in static. You can type in read only, for example, or you just limit it. Most of the time we don't have entities.
Then you have a return type so that means this method does something, and then it returns me something. And this is the type of that's something that returns back to me. So it answers the question, what do I get back when I run this method? Then you have the name of the method. So in this case it's AddToNumbers. And just like Tom said, we are using camel case here. And then in between curly braces you basically declare something called parameters, which are inputs. There what your method needs to be able to run. So this is how you pass information to your method.
Now in between curly braces, which you open right after the normal braces, you type in your statements. And this is the body of the function. So when I'm going to say, oh, please put this in the body of the method, it's in between the curly braces. And this is where you type all your statements and do stuff.
Cool. Now this looks a little bit different from Python. And we have a lot more types, and you have to declare these returns every time. And it's a little bit different to Python because this is a statically typed language, essentially. So you have to tell it I'm working with an integer, and it behaves like an integer, right? If you give it a double, it's going to complain. In Python and JavaScript, you have more loose concepts of types.
So you can be a lot more dynamic, and if you give it a double or an integer, It's just going to try and convert on the fly for you and going to try and figure out, oh, you gave me an int. So I'm just going to work with that. Whereas in C #, we have to be very, very precise about our types.
So if we tried to for example, assign-- we have a method here called math.AddNumbers, which obviously, adds two numbers, right? So it expects an integer and a second integer, for example. If we tried to passing hello to this method, it won't it won't run. It won't even compile in C #. So you won't even be able to ever test this because it will never compile. And this is where that usefulness comes in.
OK, final point, and this looks all over the place. It wasn't like that. When you declare a class, it usually has a few things inside of it. It has a list of fields at the top or properties, we'll learn about the distinction later. There's something called a constructor, which is a special method. And this is special because it's the one that is responsible for creating an instance of that class. So I have a method that can create a desk, and that's the constructor of that desk class. Then you have methods that can basically-- are the capabilities of the class and they can do whatever.
How you make new instances of things? Generally, you declare a variable, and you use the new keyword, which tells the compiler called the constructor method of this class to make a new object. So if I type in new truss, and I give it a list of points for example, it will make a new truss for me and what I get back into this variable is an instance of that truss. So here I'm making three separate instances of a truss. I could be giving it the same points, but they would still be separate instances.
So I'm going to cover this because we skipped it in the previous one, but to code in C # and to develop this we, use Visual Studio. This is an IDE, an Integrated Developer Environment, and essentially you'll see it in a second, there's a few concepts to know here. One is the concept of building a solution, which is just fancy words for saying compile my stuff. Make it work. Make it runable by a computer.
So it takes all your codes, all your dependencies, if you're importing Dynamo libraries, it takes those in as well, and it produces your program. Now what it actually produces is, depending on the type of project you have, it usually produces a DLL file. And this is that intermediate object representation we were talking about. So this is where all your code gets compiled to, and it's now ready to be run by the .NET Framework.
You can also create .exe files instead of .dlls. So you can create standalone programs that are just straight up run. Now those will run but they won't be useful to anyone if they're just a library of functionality, for example. So most of the time we want to be making lots of libraries, and then we have one program that can run those libraries and use them to interact and do stuff.
Coding time. So can everyone please launch Visual Studio 2019. It should be on your desktop. And I'm going to swap over to the computer if I can. So, if you guys go to your Data Sets folder, and I'm sorry if you can't see me over there. Can't see it? Five, you're OK. Cool.
So if you go to your Data Sets folder, we're going to be in session two. And you might want to pin this folder to your Quick Bar here. To do that, I'm just going to drag it to the Quick Access here at the top. So I can just refer to it really quickly. I'm just going to move the microphone.
OK, I'm going to go open up exercise one. And I've included sample files for both the start and the complete version of each exercise. So if we get stuck in exercise one, and you just want to catch up at the next one, feel free to just bail on it, and then in exercise two, there's a kind of a start, which brings you up to speed with where we should be. We're probably going to be using those just to make sure everyone is on the same page. So I'm going to go to exercise one start. And I'm going to double click the solution file, which is the SLN. If you have Visual Studio, open you could just go File open, solution, or something like that.
OK so, let's really quickly run through Visual Studio, and then we're going to start typing up some code. But before I forget, and I almost did forget this. I'm going to need everyone to open Chrome and make sure you open it inside frame, and not using the bar at the bottom. And go to github.com/dynamods/dynamoworkshops. And you should see this. This is the repository where all the files that we use today are hosted for all of the four sessions and all of the exercises. They also include stuff from last year, so we're mainly going to be looking at the 2019 folder.
I'm going to be pointing you guys to a very specific file where we're going to be copy pasting snippets of codes to kind of make us go a bit quicker and not type everything out. So just keep it open. Don't close it. And I'm going to be switching back and forth between Visual Studio and Chrome, if that's OK with everyone. This is also publicly available, open source, and MIT license. So when you get home, download it go nuts with it. Is everyone up to this point? Yeah? OK.
So can you please go to the 2019 folder, and then click on the Dynamo For Software Developers folder, and then click on Session 2, C # Fundamentals. Now if you remember what we said at the beginning of the day, we're going to try and pretend we're space work for a day. So what we're trying to achieve with session 2 is a C # library that can basically model the concept of a desk, model the concept of people having memberships to our kind of space business, and the concept of being able to layout of room with some desks. So we want to be pretending to be desk architects, if you will, and layout the space.
That's why we're going to get through by the end of the session. And I've split it up into several exercises. So we're going to start with exercise one, and whenever I ask you to paste-- copy paste a snippet of code, please come back to this window and just copy whatever is in between the gray background, and none of the things that are on the white background, OK? So gray background, it's code. Not gray background, it's an explanation of what I'm doing there.
So going back to Visual Studio.
AUDIENCE: [INAUDIBLE]
PRESENTER: Does everyone have their glasses on? I don't know how to answer that one. It should be great. Maybe the screens are a little bit lower quality or not. Keith, we've got someone there. Speaking to that, I'm going to change my glasses. Are we good? Yeah. OK so I'm going to give you a crash course into Visual Studio, and all the things you need to worry about, and all the things you don't need to worry about and you can learn about later.
The interface is quite simple. You have a Solution Explorer on the right hand side, which is basic your Windows Explorer. It shows all the files, all the code that is in your solution. It's called a solution because you can have multiple things inside of it, to it. We have one project called DynamoDevS2E1start. And what you need to know is that every project gets compiled to its own DLL, or its own executable. So if I have three projects, that means I will produce three DLL when I compile.
If you open up the Dynamo solution, if you download it from GitHub, you're going to see there have something like 25 projects in there. That's because they've split up the functionality into discrete little projects that can interact with each other. So there's a core. There's a user interface project. Then there's ProtoCore, which is the actual execution engine which is separate from all of this. So it allows you to keep things quite modular, unlike in Python, for example, when we saw we had everything in one file. So you can still pull up your files obviously in Python, but this enforces you kind of to do that a little bit better.
Inside the project you have something called dependencies, and we won't look at this too much in detail today, but you also have something called desk.css. So every C # code file ends with .cs. So what I want you guys to do before we kind of get any further, just to make sure everything works because demos sometimes have issues, I want you go to the menu at the top right, click on Build, and just click on Rebuild solution.
Now if everything went well you should probably see what I'm seeing here, which is the output on the screen. And it says rebuilt all, 1 succeeded, as in one project succeeded in building. That means that everything went fine. The compiler was able to take our code, put it into a DLL, and we can now continue to add more code. Is everyone's solution compiling?
AUDIENCE: [INAUDIBLE]
PRESENTER: OK, we have one with packages missing. Two. Did you click on rebuild? Did you click on build or rebuild?
AUDIENCE: [INAUDIBLE]
PRESENTER: Keith, we've got packages missing over here? By the way, this is a .NET standard so. It's here. And one more there.
AUDIENCE: [INAUDIBLE]
PRESENTER: So, yeah if you get an error on your screen saying failed to restore packages or something like that, you might need to copy that folder onto the desktop, and then run it from there because Windows has stupid limitations about how long your path can be and where the data sets are, it's quite long. OK so just raise your hand if you need assistance with that.
But without kind of anything else, I'm just going to point you to the error list at the bottom. This is basically the compiler doing the heavy lifting and providing you with lots and lots of feedback about what's happening when it compiles your code. So I can turn off the errors. There aren't any, thankfully. And it has seven warnings. So it's telling me, oh, by the way you should probably look at this. Something doesn't quite make sense, but I was still able to compile it. I can turn off all the warnings because we're not doing production code here, so we don't care about it today. But please look at the warnings when you're at home or writing code for your office, OK. Don't just ignore them.
I'm going to close the output window because I don't need it at the minute. And I'm going to double click in the Solution Explorer on desk.cs. And this is where things should start to get a bit familiar because we talked about classes, but essentially what we have here is the code inside that file. And what we're looking at is a couple of using statements, which essentially is a way of saying, oh, I want to use the functionality in this other package, this other DLL file. So please import it into this code file, so I can use it. So when I say using autodesk.designscript.geometry, there should be an Auto NAT DesignScript that geometry yellow somewhere, and it should be able to import it.
Now I've already prepared the solution, so it's got everything you need in it. If you want to know how that's done go to the GitHub file-- sorry, go to the GitHub site. We don't have time to cover that today. And I found that it really doesn't help in demos in classes. But that teaches you how to do it on the site if you need to look at it.
The next statement is something called namespace, and this is just a fancy way of saying this code that I am going to write in between the brackets that follow namespace belongs to this group or this kind of functionality. So it's a way of saying, oh, I'm going to package up all the my functionality to this group. And you can go namespace dot something else to kind of make a subfolder of that and group your functionality there. So it's just a way to organize your code. It has no effect on how it runs. It's just a way for you to kind of keep it organized and clean.
You see for example autodesk.designscript.geometry, that's the full namespace for that particular project. So anything inside that project is going to be autodesk.designscript.geometry dot something else, essentially, every class. So our namespace is dynamodev, and then we have a class inside of this. Our class is declared using the public access modifier. And then we type the keyword class, and the name of the class, which is desk. We open curly braces, and then we can type code.
Now I've prepared this file to have one property. So what we're going to do now is we're going to add a few more properties, and then we're going to add a few more classes to go through the motions. And then we're going to have a tiny little library that knows how to do a desk and a person and a few other things, OK?
So I'm just going to quickly check GitHub to see where we are, and what we want to do is add a few more properties, like length, height, width, and maybe the price of a desk per day because we're a space provider. We care about how much money we make. So I'm going to go to Visual Studio, and I'm going to enter some new lines, and I'm going to declare a few more objects-- sorry a few more properties. The same way that length is done. I'm just going to change the name of the property of this instance. So I'm going to I type in public, double, height. I'm going to use that same get set statements as above.
Now explaining what this does, we're declaring a property called height. It is public so other people outside of our code will see it. And it's of a type double. So that means it's a number with a decimal point. The bits after height are a nice kind of feature of C #, where if you declare a get and a set, that means that this property can be get. So I can get the value of this property. And I can also set the value of this property.
If I were to, for example, go set, I could set the property of-- sorry, set the value of this property, but I could never get it. If I tried to get it, it will tell me denied. So this is a handy way of kind of managing access. Yes. Although I don't think you can actually just set. I think you always need a get with a set, but you can have a get and not have a set or have a private set, for example. So only the class itself can set the value.
We won't go too much into detail about the distinction between properties and fields, but just know that this is syntactic sugar from the C # compiler allowing us to write less code. If you look at the snippets, I've actually included what this code would actually generate out to. It would-- the C # compiler would make another field in the background for you called length with a small l, and whenever you get the one a capital letter, it actually gets you the value of the small one. And whenever you set it, it sets the value of the small one. This is just a way to manage access and make sure that we're not kind of hitting the same object. And I won't go into more than that because it can be a full day just on that.
So we have a site-- height, let's quickly add a width to the desk, and then we'll add a price. So I'm going to go public double width. And just to show you why I said that Visual Studio and C # are a lot friendlier and a lot more productive to things, you can see that I'm typing a lot of the same stuff and just changing the name of it. And I could copy paste.
Or, for example, you can type in prop, don't press anything afterwards. And the little box you see underneath is something called IntelliSense, where the Visual Studio program kind of tries to figure out what you're trying to do and provides suggestions of what your code should look like or what the available methods are or what properties you could use. In this case prop is a snippet.
So if I type prop and then I hit Tab twice, it will autocomplete to a full property. And it'll automatically jump to int, so I can type in double, and then tab, and it jumps to the name of the property and I can call this pricePerDay. And for a pricePerDay, I'm going to delete the set here because I only want to be able to get the pricePerDay. I don't want to be able to set it from outside because you know intrepid users would just set it to 0 and not pay. Any questions so far on making properties? No?
So in the previous class where Tom was accessing wall.id for example. What he was doing is he was accessing the id property of the wall class, which is what we're doing here. We're declaring these properties of those classes. So this will hold data. This is where the data will sit and we will be able to access it.
So going further, what we also want to do is we want to basically assign a desk to a person because this is a kind of co-working thing, people don't have set desks, or maybe it's hot desking or something. We want to know who is currently sitting on that desk or if it's reserved to a specific person. So I'm going to declare a property called public person occupier. And I'm going to go get set. I'm just going to quickly check my snippets that I want it to be a get set.
Now what you'll see here is that well, you've got the red squiggly line under person. And if you hover with your mouse over, it, says the type or namespace person could not be found. Are you missing a library or something else? That's because we don't have a person class. The Autodesk library doesn't have a definition of a person, and neither does the kind of built in system C # library. So what we need to do is we need to make our definition of this type. So we're going to make a new class.
Now we could make a new file, or if you hover and you go to this little light bulb icon, it should actually give up a suggestion, oh, why don't you generate the type person. And I'm going to go click on generate class person in a new file. And what you'll see on the right hand side is the new person.cs appeared in my browser. And if I double click it, it automatically put it in the same namespace. It declared the class for me, and I can start adding code to this.
So this is how productive and kind of useful Visual Studio is. I don't have to right click, make a new file, type in the name. I can just declare right I need and use these kind of suggestions to get really, really productive. If you start knowing the keyboard shortcuts, you'll be essentially flying through this. Everyone up to here? Everyone got the person.cs file?
OK, so what properties do you think a person should Have if we go back to here. I'm cheating by showing you what it should have. No, still no ideas? OK, let's go ahead and make them. Now I'm not going to make you type name and email again. So I'm just going to select them. Copy and I'm going to paste them inside the class just to save some time.
And essentially what you should get is red squiggly lines under this type called guid. Now any now anyone know what a guid is? I have one. So guid is a globally unique identifier. So that means that there is a almost guarantee that this string, this text, is a globally unique text. So if I give you an ID it'll something like ABC123-F9 something something. It's a long string, right?
And then when I say it's almost guaranteed, it means that it's going to try and generate a unique one. And there's like a 1 in 10 million chance it generates two that are the same. So you can generally rely on them being unique. Anyone use the in Dynamo Revit it element.id that's usually a number. Those are very hard to make unique. So what you usually use is element.guid or other things which are the specific type which are more unique.
So it's under red squiggly lines because we don't have the using statement for this. So I'm going to hover over it, hit the light bulb, and the first suggestion is addUsingSystem. So I'm going to click that. Adds it at the top, so now I can access that class, and I can do what I needed to do.
So now that we've defined this person, I'm going to click control+S or save here at the top. And I'm going to go back to my desk.cs file, and you'll see that person is no longer underlined with red, which means that it can find this class and use it. So I've just declared a desk. It has a length, height, width, pricePerDay, and also has a person that is currently occupying that desk. So we're starting to kind of get a sense of what the business of space work might be here.
So what are we going to do next is we're going to look at membership. So back in the person class, I'm going to add one more property, and you can feel free to copy paste this snippet, and I'm going to do the same public membership. And I'm going to call it membership. And again, it's a red squiggly line, so I can hover over the light bulb, generate the membership file in a new class. So I the class in the new file. And if I go over to it, this is called public class membership now, and I can add some properties to it.
Now what do I want with a membership? I want the membership to be unique. So I don't want people to share memberships. So I would need something that can be identified. So I'm going to add a guid, another identifier property. And I also need to specify what membership type this is. So I'm just going to quickly add these. So I'm going to say public guid and this is a get set. And again squiggly lines means hovering over using the suggestions. And then I'm going to type in public string Type with a capital T. And I'm going to use it get set again.
But looking at this, if I were to declare my membership type, like for example, co-working, or a dedicated, desk or a private office, I would have to basically spell it out as a text private office every time I wanted to use this functionality. That wouldn't be very clever because I'd have all of this text laying around, and if I spell it wrong once inside these brackets-- or sorry inside the commas, I invert the commas, my program essentially be wrong. It would compile, but the logic would be wrong.
So when you're trying to define something that has a limited set of possible values, you use something that's called in C # an enum, which is an enumeration of something. So what I'm going to do is I'm going to come out of this membership class underneath it and add two more lines, and add something called a public enum membership type. I think that's what I called it. Then I'm going to copy paste the possible values from the snippets just because I'm lazy and I don't want to type.
And what you see here is me declaring an enumeration of possible values. I'm saying the membership type can only ever be coworking, dedicated desk, private office, or enterprise, if you're so lucky. So I never have to type in these values again. I can use them, and check that my member has the specific membership type. And I don't have to retype private office every time. I can use these as if they're properties, and as if their code. And so this is very useful to declare possible values. Revit has a lot of these built in to kind of define what type of, I don't know, wall or beam or things like that.
We're going to keep moving because I'm not sure how we doing for time. So now that we have some methods-- sorry, some classes. We have properties to all of them. I'm going to hit Build, and rebuild solution again. And hopefully it all builds OK. Everything is fine. And what you'll notice is that it's not exciting. You don't see anything. It hasn't produced anything that you can interact with.
And this is one of the things that Dynamo excels at. It allows you to have this environment where you can see what you're doing and get immediate feedback. What you'll notice when you're writing code is a lot of the time you're writing code that compiles, but you have to build a separate thing to actually test it and see how it behaves because you're just flying blind here, essentially. You're typing in text, and it could work. It could not work. You have no clue.
So what we're going to do next is we're going to add some methods to these classes, and what time do we have to stop 12:30? OK, I'm going to go a bit quicker now guys. You OK to go a bit quicker? Yeah, OK. So let's add some methods. And like we said earlier, methods are basically capabilities that our objects can have. So each object will have very specific capabilities.
So for example, the desk has a width, a length, and a height. So I can calculate the volume of a desk. Now I don't want to add this as a prop. Because if I change the length, I want the volume to automatically update. And if it was a property, it would never do that. So instead, I added a method called volume. And this will calculate the volume for me.
So I'm going to copy this snippet. I'm going to go to my desk class, and I'm going to close the error thing. And just below all the properties, I'm going to add a few lines and paste it in. Just like we saw before, we have a public access modifier. We have a return type, so a volume is a double. And the name of the method. I don't need any inputs because I already know the length and width of the desk. And again this volume, whenever you run it, it runs on that particular instance of that class. So it doesn't need to be told the length of the desk because this method already belongs to that particular desk.
So what I'm saying here inside the method is return, which is the keyword you use to actually give back a value, and I'm using this.width, which is a very kind of clear way of referring to valuables. When you say this, you mean this object length. So there's no ambiguity here. There's no length. I'm passing in. You know for certain it's the length of this desk.
So I'm just doing a simple multiplication here. This is math. All of these values are already doubles. So I don't need to convert any types or do anything special. So I'm just returning that calculation. I'm going to do the same for area and price for a number of days. And paste the snippet. And you'll see area looks exactly the same because it's the same calculation.
But for price for a number of days, suddenly you have something else in between the braces, which is int days. This is the way you define a parameter for a method, which means to be able to calculate the price for a number of days, I need an extra parameter. I need an extra input called tell me how many days. So I'm declaring an integer called days, and then when I calculate I return, the number of days times the price per day for that particular desk. So this is where I'm combining an inputs that is external to my class with a property that is internal to my class to make a calculation and give you back a result. Any questions on that? No, OK. Let's keep going then.
So what if-- so far we're only calculating things. So what if we actually want to change stuff. We have a person that is assigned to a desk, an occupier. So how do we actually assign this desk to someone? So what we're going to do is we're going to type it out, a new method, make some lines, public void assignDesk. And I'm going to open braces.
Now the return type is void here because I don't need to actually return anything. I'm just going to do something and not return anything to whoever is calling this. In between the braces, I'm going to say person, what did I call it here? Oh no, it's actually this-- oh, we're doing this in the wrong class. So I don't want to assign a desk to a person inside the desk class. I want to assign a desk to a person. So I'm going to do that in the person class.
So go to the person class. Add something at the bottom called public void assignDesk. This keyboard is terrible. And I'm going to take in an input of desk type desk, and I'm going to open curly braces that will actually do something. So what I wanted to do now is given a parameter, a desk, as a kind of external input. I want to go this.assignedDesk, which is a property we've made earlier is assigned the value of that input.
Now what-- oh sorry, the assignedDesk should not be a guid. It should be a desk of the property type up there. Now I've assigned the desk to the person, but the desk. I've just passed in doesn't know it's been assigned. So I also need to update that object. So underneath this, I'm going to type in desk dot, and I'm going to scroll down. And this is where Visual Studio gives you all of the available methods, which are these little cubes, and the properties, which are the wrench.
So I'm going to look for a property called occupier. And I'm going to assign it the value of this, which means I'm passing in this desk to my person class, a particular instance. And I assign that desk to that person. But then I also tell the desk, oh by the way, you're occupier's now me. It's this instance of that person class. So it's the same as going desk.occupier is this person, essentially.
I'm going to save. Let's just build to make sure that everything still builds. If everything still builds, we're OK. So we're going to keep going. We want to do something else to a member. We want to be able to change their membership. So if you have a coworking membership, you can upgrade, and downgrade and do all of these things. I'm not going to type it out because it's a bit long. So I will copy paste it. And I want you guys to paste this underneath the assignDesk method. And I will walk you through what this is doing.
We have a public method called changeMembership. It returns a boolean, which is a true or false. And the reason we want to do this is this is a little bit of a more delicate operation. We want to know if we actually change the membership of someone or not. We don't want to-- like if it failed, we can't assume that it went through, for example. We want to know the person has been assigned to that membership. So we will return true if we can assign it and false if we haven't assigned the membership like it was requested. The input to this the parameter is a membership.
So the next thing we do is we have a keyword here that is new to you guys, which is the try catch keyword in C #. If you type in try, you open curly braces, and then you can type your code in between that. Whatever code is in between those curly braces, if it errors out, if it explodes, if it does something really, really bad, and your code just goes like [EXPLOSION SOUND], it will catch it.
So, try doing this. If it runs fine. If it doesn't run, the next expression catch will basically catch all of that trouble, and you can deal with it in the catch method. So if you've ever opened Dynamo and you had like a crash, for example, and you get the little Dynamo icon with like the crossed out eyes and a really sad looking face, which is an amazing icon by the way, that is basic an exception, an error being thrown. Something exploded and no one was there to catch that.
So the program doesn't know how to deal with that, so was just going to self-employed, and go bye bye. So this is why you want to introduce error handling, this is what this is called, or exception catching, as much as possible in your code. Try to catch the possible errors. So what we're doing here is we're saying, OK so try to assign the membership. So this person's membership is being assigned this new membership.
And if, by whatever reason, the new membership we're trying to assign is actually a null value, which means nothing value or there's no membership that was initialized or we're just passing in nothing, actually we're going to throw an exception, which means that this block of code will catch it. So we will return false. No, we were not able to assign the membership. Otherwise at the end, yep, we were able to assign it. Nothing caught. So we will return true. Yes, we did assign the membership to that person. Any questions on this one because it's a fairly new topic. No? One.
AUDIENCE: [INAUDIBLE]
PRESENTER: So if argument null exception is not working, hover over it, and you should get a light bulb and it should give you a using suggestion. So you shouldn't have using system at the top. Keith, or Aaron or someone if not have a look there. Yeah?
AUDIENCE: [INAUDIBLE]
PRESENTER: It makes sense, if-- check that the desk is a desk type because I think I typed it out as a guid earlier, so I made a mistake.
AUDIENCE: [INAUDIBLE]
PRESENTER: Can I go over the membership file again? OK, we're going to skip ahead a little bit just in the interest of time, we're not doing too great. So I'm going to run through exercise two just by showing you guys the snippets. So then we can get to the fun stuff, which is exercise 3 and 4.
OK so everyone's up to this point. So the next thing we were going to look at, and we'll just do one of them. We won't do all of them for the sake of time is these special methods we called constructors. So we want to be able to construct a new desk object or a new person object and initialize it with some default good values. And we do that in a constructor method.
So for example, I can go, copy this snippet from the people constructor bit on the page. I can go to my person class, and somewhere in between the properties and the methods, I can paste that in. And it should say public person. And you'll notice that the name of the method is exactly the same name as the class, which is what makes it a constructor. And I'm basically assigning this.name name as a John Doe. And this.membership is a new membership, which will be initialized as nothing, essentially.
So whenever you type in, oh, variable x is a new person. This code will run. This is why it's a special method called a constructor. So whenever we have the new keyword, it will run a constructor method. And why it's important to have one of these is so that you initialize the values with good default values or possible values. If we didn't, the name would be null, which means nothing. The membership would also be null, which means nothing. So we would have a person that is a bunch of nothing, essentially. At least this way we can have a person that we can assign a John Doe name until we know more about them, and a default membership, which is a no membership.
I'm going to scroll through the rest of the constructors. We can do the same thing for a desk, and initialize a new guid, a new price per day. We can say, oh, maybe it's $35 per day by default. And an origin, we can say point by coordinates. And this is us using the same syntax that you're used to in Dynamo, point value by coordinates. This is part of that Autodesk DesignScript package that we're importing.
What if you want to make a person with a name? So you make a new person, but you also want to specify the name at the same time. Well, you can have other constructors with parameters. They don't all have to be empty. So for example, if I copy paste this snippet, and I paste it underneath person, this is a second constructor. And I can have that because it's got a different signature, meaning I actually have a parameter in this one.
And what I'm doing is I'm calling this which is the constructor above it, the one with no parameters. So it's going to use that one first. So it's going to initialize the name to John Doe. Then it's going to check if the name I'm passing in, is it a null or a whitespace, which means I passed in nothing or I passed in like spacebar couple of times or something like that. And if it is a blank name, I'm going to say uh-uh. You can't give me a blank name. I'm going to throw an exception here.
So get in the habit of at the top of your methods or constructors, very first thing you do is you validate your inputs. You don't do anything to your object before you validate the inputs. If the input is valid, you can continue. If the input is not valid, which is what you usually end up checking for, you throw exceptions. And you don't care if someone catches it or not. That is someone else's job to catch it, essentially. So what we're doing here is the name valid, if it's not, I'm going to throw an exception. And if it's valid, I'm going to continue and actually assign the name.
OK. The very last thing we're going to talk about is a static method, which is different because by being static, if you remember, it means it's not associated to any one person. So it's associated to the person class, but not to this person or that person. So it can work with just the person class. So these are useful, for example, when you want to make a constructor that just takes in some parameters and spits out a new person.
So we're going to-- let's copy paste thus snippet actually. And put it underneath there. So it's public static person, and it's saying by name email and membership. So I have a parameter for name, one for email, and one for membership. So I have all of these inputs. You'll see red squiggly lines because it says not all code paths return a value, which means I need to return a person when I have a method like this. I've declared that I'm returning a person, so I need to return a person.
So I'm just going to copy paste the snippet below it, which you see us having a variable called person. I'm initializing a new person with that name, which is using the constructor that we did earlier. And then I'm setting some properties. The email I'm setting it to the email I have here. And the membership to the membership I'm passing in. Now I won't copy the other snippets, but essentially, what you should do before assigning any of these values is you should have checked if the name, email, and membership are null or not, and throw errors if they are. Is that kind of part clear?
I don't know if you've noticed, but the name of this should be quite familiar by name, email, membership. This is a convention that Dynamo uses, for example, when it makes a new object. So point.byCoordinates is a static method that takes in some coordinates as parameters and spits out a new point. Internally, it's doing the same thing. Checks if those inputs are correct. If they are, it makes a new point object, and then returns that new point object to you. Question in the back.
AUDIENCE: [INAUDIBLE]
PRESENTER: Why would you do that? So it's a good question. There is a lot of debates about this. You can go into depth quite a lot. But yeah, when you have a constructor it automatically assigns those things to a particular instance. This is a method where you don't-- you can give it some inputs, and you'll have logic in there that, based on your inputs, it will create the right kind of person with the right kind of values. This is a very simplistic example.
So what you should be having here inside of it, for example, is deciding, oh if you gave me a minus 1 for the x-coordinate. I'm going to mark this property in the point class as oh, it's negative or something. So it's doing more work essentially. Constructors you don't want to have a million of, where these you can have 10 of these static methods that allow you to build objects differently. You also don't need to have these on that particular class, either. So I can have this method on any class really, whereas the constructor is tied to that class. We're going to keep going because we're not doing amazing on time either.
So static methods, this bit we can safely skip, but I can just tell you about it. You've seen us type guid and id for the properties of each one of these things. Person, membership, and desk, we can identify each of them with an id. So wouldn't it be nice if we didn't have to copy paste all that code around? So if we didn't have to say the person class has an ID. The membership class has an ID. And the desk class also has an ID.
So what we can do to make it easier for ourselves, we can define, because remember everything is an object, the fact that they are identifiable into a class. So I can say public class identifiable. I can declare the id on that class, and initialize it with a new id. And then what I can do is I can say, oh, this person class inherits from identifiable, which means that every single property and method that is in the identifiable class gets automatically put into the person class as well.
So whenever I initialize a new person, it automatically underline kind of initializes this new id. So it means that I don't have to repeat the id property on any of the classes that inherit from identifiable. you can only inherit from one thing in C #, so you have to choose that wisely. And in Revit example, every single Revit element inherits from something called Revit.element, which is kind of the base class for all elements. So they didn't have to repeat themselves. Everything is a base element, and then you have more specific elements on top like a beam element, which has a few extra properties as opposed to the base element.
OK so let's go back to the data set. I'm assuming everything in Visual Studio still builds. You can check that if it rebuilds, it rebuilds fine. I don't want to waste time on that. So I'm going to go back to the data sets to the folder I pinned. Let's skip to exercise three and let's go to start. Because this is the exciting bit. I want to make sure we cover this bit. And then exercise four, we can have a very brief look at.
This exercise is the one where we've already defined a desk, a membership. We can make these things, assign a membership to person, assign a desk to a person. So we've got the business logic kind of wired up. What we want is now, give me a space. And I will layout desks on that space. So we need the logic for that.
So what we're going to do is we're going to make a new class called desk architects because the job of that class is to make desks in the space. So it's the most boring kind of architect you can get. So going back to the snippets. We can make this class. But what I want to show you is that we have a few extra things in our starter file here. We have a utils folder. And if you look at it, it's a class called geometryUtils.
I didn't want to have you guys type this out, but it's a method that basically takes in the surface and the number of points. And it basically subdivides that surface with a grid of points. So if I have a surface and the number of points is 10, it's going to generate a 10 by 10 point grid on that surface. But it follows the kind of uv coordinates of the surface. So it's just a utility method that we're going to use in our layout algorithm. It's already there for you. So is anyone missing it? No, OK cool.
So what we will do instead is we will right click on the project, go Add, New Folder, and we're going to call this Layout because we want to keep this functionality separate from our kind of other business logic. And I'm going to right click on the Layout folder and go Add Class. And I'm going to call this, once it comes up. I'm going to call it desk architects. And by the way, feel free to call it something else, but the other examples might not work if you do that. I'm going to type in public in front of it so I make sure that it's accessible from other places.
And now I'm going to go back to my snippets, and I'm going to see that actually I should make this a static class because I don't want to initialize a new desk architect everytime I want to make a layout. No, I want to have one desk architect that knows how to lay out things. So I can make that class static. I don't need a bunch of them laying around.
And then the first thing we're going to make is a method. So I'm going to copy paste a snippet. And again, I'll make that static first. And then inside of it, I will paste this method. And open the curly braces. You'll notice that we don't have to have properties on this class. We just have a method. That's all it's going to do. If you have a red squiggly line under surface, hover over it, use the light bulb to import the Autodesk DesignScript geometry using.
And then inside of the layout desk on surface, what are we going to do first? We will basically check the input. Let's check if the surface is valid. And then once we check that, let's initialize a list of this-- sorry, a list of desks to make sure that whenever we start making desks, we can put all of them in a list, and return that at the end. This is very similar to what Tom was doing in the first session where you initialize the array first, you give it a name, and then you add objects to it later on.
So I'm going to copy paste that first snippet. And you see that this is very good practice, and if there's one thing you take away from today, validate your inputs first. There's nothing that is more annoying than having a method or something that never validates inputs. You assume it works, and it just doesn't work. So do your validation first. Bail, throw errors, return falses, and then only if all of those pass and everything is good, you actually have your code.
So we've initialized that list everything is fine. I'm going back to my snippets. So I'm going to use that utility method from geometry to basically make a bunch of points. So I'm going to paste this in. I'm declaring a variable called points. I'm saying oh use the geometry utils class, which I need to hover over and add the using for. And you'll see that I'm using DynamoDev.utils. This is because in the geometry utils class, the namespace is DynamoDev.utils. And by default, if you put a cs file in a folder when you make it, Visual Studio would add that namespace to you. So it's a very handy and nice way of organizing code.
So back to my desk architect, I have a list of points I'm making. So I'm taking the surface. I'm generating a list of points. And if you ever wonder what type of something is, just hover over it. I'm hovering over points, and you can see that it's a local valuable, and it's actually a a list of points. So the next step going back to my snippets, is to actually make a desk instance for each point. And I will just copy paste that snippet.
And this is the first time we're seeing this. Is a for each loop. Now you should all be familiar with the concept of looping. You're doing something over and over and over and over again during construction. We're familiar with that. So this is just saying, OK, for every single point in that list of points, do the things in between the brackets. So I'm taking each point sequentially and doing something for that point.
So I'm taking the first one, I'm saying, I'm going to make a new desk. And I'm going to set the origin point of that desk to be the point. We didn't cover this because I skipped through that a bit just to save a bit of time, but we did add the property on the desk class called origin. If you ever wonder where these things come from, again, just hover over them. You'll see that point.origin is desk type, so that means that the desk class has a property called origin that is of the type desk. No, sorry. I got that completely wrong. The desk class has a property called origin of the type point. I'm getting tired. So if I make mistakes, correct me. OK, cool.
So I've made I've made these points right, but I'm not actually doing anything with them at the minute. I'm just making a new desk, and I'm setting the origin for it. So actually want what I need to do is at the same time as making it, I need to go desks.Add and I need to type in my specific desk. So I'm making a desk for every point, and as I make it, I add it back to the list of desks. And then at the end, I just simply return the list of desks. Any questions on this bit? No? OK, we've got, I think, 15 minutes left. Yeah? We ran over. We can run over again. OK I'll try to be quick. 10 minutes then. Negotiating.
So is everyone up to here. Are we good? Are you enjoying coding, but not seeing your results. No? Welcome to development. So what we're going to do is go through the last exercise, and then I'm going to show you the actual fun bit, which is seeing what this looks like in Dynamo. The next session after this will be Tom going into a lot of detail about how to get these things into Dynamo with even more precision.
So if I build this, go rebuild solution, you should see everything succeeds. Everything is fine. And actually, let's do it now. Click at the top here, aah. I think this decided to-- OK, never mind. Don't click on anything. Let's just go back to our folder, and go to exercise for, and open the start file for exercise four. Actually, I'm not sure we should-- we need to do that. I think we can just continue. But just in case, I put something in there that I'm casually skipping over because of time. Let's open that exercise four start file.
The only thing have done differently here as you'll see that I've organized my code into folders now. So I have a business folder. I have a layout and a utlis. This is just a way of saying oh package up the functionality with the right kind of group. So I have a business namespace because this is the domain knowledge of that business, desks, memberships, and things like that right. So I just put all of them in a folder, so it's nice and cleanly organized.
So the last step we want to do is we have a class now that can lay out desks in a space. It doesn't use fancy logic. It just spaces all of them out equally. And it just returns a list of desks. That in itself is not very useful. So what we want to do is return a more structured object, which has those desks, but it also has some metadata, if you will, some information about that arrangement of desks. How efficient is this arrangement? Who made it? When was it made? What were the inputs to this? Things like that. You want to know how that output was generated.
So what we're going to do is going back to our snippets, we're going to make a new class. So I'm going to go back to Visual Studio. I'm going to right click on Layout, and go Add, Class, and call this desk arrangement. All right, and I will make my class definition be a public class. And it inherits from identifiable.
Now another top tip in Visual Studio, if you're somewhere in code and you see one of these things light up, you can actually peek the definitions or go to those definitions if you want to see it. So I can right click on indentifiable and go peek definition, and you'll get a little window that basically gives you a window into what that class is doing. So you don't need to go looking for that class. You can just right click on it, peed definition or go to definition, see what it's about, then when you're done, close that little snippet, and you're back to doing your stuff.
So I'm going to go to my Chrome snippets, and I'm going to just copy paste all of these properties because I don't want to type them out. And I will talk you through what each one of these is doing. So I'm basically making a class called deskArrangement, and this going back to that object oriented programming, I'm representing the output of my layout activity in a class. And that's called deskArrangement.
So this has to have a list of desks, which are the things I've laid out in my space. I should also have maybe a date timestamp when it was created so I know when this design was generated. And I can see if it was 10 years ago, I can safely assume it's out of date. I can also then have statistics about this. So I'm going to have a property called desk count. I'm going to have a property called actual yield, which is a measured efficiency of the space. How many desks did I fit per square meter for example.
And then I can have a target yields, like what are we targeting. Maybe we're targeting 78 desks per 100 meters. So then I can calculate the actual one. And then if I divide the two, I can calculate the efficiency of that space or desk. arrangement, essentially. These are properties holding data. You'll see some of them, like actual yields, this little arrow means it's redirecting-- whenever you tried to get to this property, it's actually calling the method called calculateYield. We don't have that method yet. So that's why it's in red squiggly lines. So we're going to copy paste these guys next.
So I'm going to go back to Chrome, and I'm going to copy the calculate yield method and paste it in there. And make sure you go back to the right Visual Studio solution. And whereas is it? Nope, that's not the one. It should be this guy. Oop, I'm sorry. I've done that in the wrong file. So I'm just going to do that again here really quickly in Layout, New Class, deskArrangements.
And you'll see that I made a typo here. So I can use Visual Studio to rename this, and just go desk with only one e. And it should rename the file as well. Visual Studio is smart like that. It helps me. I can copy paste the properties again. I can make this class public. And then I will copy paste the methods for yield and efficiency because they're boring calculations. We don't need to spend a lot of time on them. But the yield is basically desk count over the source surface area. Now we don't have that yet. So I'm going to ignore it for now.
And then I'm going to copy paste the efficiency method, which, again does a simple calculation of is the target yield 0. We want to check for that because we can possibly divide by the value 0 and if it's not we actually calculate the actual yield over the target yield times 100, which means it will give us a percentage back.
AUDIENCE: [INAUDIBLE]
PRESENTER: Yes. Good spot. Identifiable. Well, I don't have it in this sample file, so--
AUDIENCE: [INAUDIBLE]
PRESENTER: Hm? Oh. Identifiable. OK, so using DynamoDev.business, I can import it. And it's now there. You'll see that this source surface area is missing. This is because when I make the desk arrangement, I want to give it some inputs. I want to tell it here's the list of desks I generated, and here's the surface I generated those desks for.
Now that surface is not something I want to expose in the desk arrangement. I don't want to say-- that be part of the results because it's not needed. It was used in the inputs, I no longer care about it. But what we need that source surface for it is things like what was the area of that surface so we can calculate our efficiency, which is why I'm passing it into the constructor.
So I'm going to go to the snippets real quick. We're very nearly there guys. And I will basically just copy paste this complete snippet, the public desk arrangement one. And I can put it down at the bottom. And I can hover over the source surface area, hit the light bulb, and then click on Generate Field, so it generates the field for me. If I scroll up, I should see the source object. And this should be a surface type. And the reason it didn't know how to generate that is because I need to add the using DesignScript.geometry thing. So again hover over it with a light bulb, and click on the using Autodesk DesignScript geometry hint.
So I'm back here at the bottom. This isn't happy because this isn't a surface actually this is a double because we're just recording the surface area. So in the constructor, going back to what I'm doing, I'm passing in a list of desks that our desk architect laid out, the surface that it was laid out on. So I'm recording the desks. I'm recording the area of the surface just by going surface.area.
And I'm not doing anything else with that surface, and then I'm setting a default target yields. And this default efficiency target isn't defined, so I can click the light bulb icon. And I can generate the read only property at the top. And if I scroll up, it should have put that somewhere in here for me. And I can essentially define this to be a constant.
So what I've just done is I've added the key word const This is another access modifier just like static, for example. I've made this particular field on that class constant. So it can never have any other value, which is why I've spelt it out in caps for example. It's a double, and I'm assigning a default value to it 10. So whenever you make a new kind of desk arrangement class, it defaults to a target yield of 10. And you can overwrite that if you want. But if I'm doing this so that I always have a value there and I'm not dividing by 0.
And I'm just going to quickly check the snippets to see if there's anything else that I need to do. OK, so I now need to go back to my-- I'm going to copy the last snippet. I'm going to go back to my desk architect class. And you see here on layout desk on surface, I'm returning a list of desks. Let's change that to be deskArrangement, and as soon as I start typing I should get a hint. So now when I lay out desks, I'm no longer getting just a random list of desks. I'm getting a full desk arrangement object, which kind of encapsulates all of the logic and statistics about this arrangement. And then at the bottom, I basically need to change this return desks to actually return a new arrangement object.
So I'm going to paste in my last snippet, which is to new desk arrangements. So I'm making a new deskArrangement object from the desks I've just laid out as a desk architect and using that surface that was passed in. So minimal changes to my desk architect class, but it now knows how to return a very useful deskArrangement object. Any questions? And if not, I can demo this in Dynamo really quickly. And you can see what you have made because it's just code, so you don't get any feedback at the minute. No questions? Ready for Dynamo.
OK, so most importantly, hit Build at the top here. So go rebuild solution. If you get a 1 succeeded, you're good to go. If not, we can deal with that later. So what I will do is I will go back to my desktop, minimize everything, I will open Dynamo sandbox.
And this is a top tip, if you guys are using Dynamo and developing for it, unless you're developing for Revit and specifically need Revit functionality, use Dynamo sandbox. It's just so much faster to start. Not in this frame instance, but generally. And you can use it just like the full Dynamo. The only thing you don't have access to is the Revit inside of it. So I don't think I've actually used Dynamo Revit in years. I just use sandbox to test all the code. And I only use Dynamo Revit if I need to make Revit specific code. The code we've written today is as general as it can get. It doesn't know about Revit. It doesn't know about Dynamo. It doesn't know about anything.
So hopefully you get Dynamo starting up. I'm just going to hit New. And because the library is missing, by the way this is-- we need to fix this bug. You need to start it several times before you get the library actually showing up. So let's-- if you get that started, again, close Dynamo start it again. And if you go New, you should have the library here on the left hand side.
So what I'm going to click on is File, Import Library. And I'm going to navigate back to my data sets. Or I pinned at the top, so I'm going to go to Session 2 C # Fundamentals. Go to exercise four, which is the last one we were working on. Let's go to the one that I've completed earlier. Let's see if things are in there. So go to exercise four complete.
Go to a folder called bin. So this stands for binaries, which is the compiled objects. Go to Debug, .NET Standard 2. And you should finally, after all these folders, find DynamoDev.dll This is the actual output of our code. So when we hit Build, this is what gets produced, a simple .dll file. You can see it's 10 kilobytes. So it's extremely tiny. And hit open.
As soon as you hit Open, Dynamo should put a Dynamo dev package here in addons Does everyone see that. Cool. So if we now explore this, you'll see Dynamo Dev, you'll see Business. OK we have our grouping there. You'll see desk. And you'll see that I have a plus for desk. My scroll isn't working, so I'm going to do this manually.
So I, for example, could click this and I'll make a node here that says desk. I can then, for example, click on area and feed it a desk, and that node will tell me the area of a desk. I can also use that id node and feed it a desk. And it will give me the id. So this is what those guids we were talking about earlier were.
This is zero touch in action. I won't go into detail because, I don't want to steal Tom's thunder. He will show you exactly what happens to get to this point, but essentially Dynamo makes all of our codes show up as nodes. We didn't have to do anything. This is all for free. It's very, very kind of easy and powerful to get code into Dynamo like this.
So let's very quickly kind of build up a workflow. Oh damn. This isn't the Revit. So I am going to have surface. am I? So let's go with cuboid by length. All right, and-- so quickest way to get a surface, flat surface in Dynamo.
AUDIENCE: [INAUDIBLE]
PRESENTER: Rectangle, not cuboid.
AUDIENCE: [INAUDIBLE]
PRESENTER: There we go. So we're doing rectangle by width, length. And then we're doing a surface by patch. Yeah by patch. So I'm feeding in the rectangle. So if I switched to my Dynamo geometry, I will actually just put in a code block here somewhere. I think I'm not going to have very much luck with my-- OK, I'm going to go 100, just so it's a little bit bigger. Maybe 100 is too big. 10.
So I have a surface. Does everyone have a surface? We are actually using Dynamo for this. So I have a surface. So I am going to go back to the library, and I'm going to go to Layout, the method for layout. You'll see we have desk architect here. So I'm going to expand that. And we have a method called layout desks on surface.
So if we take this guy, you'll see that a once an input as a surface. So I'm going to give it that surface. And it spits out Autodesk arrangement object. It started to run. Now I'm afraid that I might have done too large thing, and it's just thinking a lot. So Dynamo's still thinking. I don't know why it's thinking so long because this is a very simple thing, but it might have to do with the size that I've set.
I'm just going to quickly save this graph to my home page. I'm going to call it desks-- on my desktop, sorry, just in case Dynamo crashes. And when I wanted to show you is if you expand deskArrangement, you can actually get the result of the desk architect method, and feed it the deskArrangement, and you can get the number of desks and all of these statistics. It's just Dynamo has not finished running this. I'm going to save and start Dynamo again just to see what's going on.
There it is. So I could go to Visual Studio here, and I could go to debug, and attach to process, and attach to the Dynamo process, and actually debug it. I just didn't do it. You'll see in the next two sessions, we're actually using this Start button to actually automate a lot of that stuff for you. So when you click Start, it will make a package, deploy it to Dynamo, start Dynamo, and you're already debugging. So it's a bit better experience.
But this session was focused on C #, showing you the fundamentals of it, showing that you can model your business ideas and your knowledge and your methods into actual code that you can then use anywhere. So you don't have to write Revit code. You can just write C # code, and then use that in Revit later on. Dynamo has stopped working.
OK, we'll debug it in the break like you guys will be having lunch. So do we have any questions? No, does everyone understands why this is useful, or is this useful? Resounding yes. Anyone, give me one, just one yes. Thank you. All right. Let's take a break and we'll see you guys in an hour. Is that the plan? I think so. At 1 o'clock, be back here. No? So 1:45, or 1:30. I think I ran over a bit. So 1:30 back here.
标记
产品 | |
行业 | |
主题 |