 Welcome back, video number six in this series on CAD from Scratch. In this video I want to talk about primitives as they relate to, you know, CAD as well as mostly just the data structures required to code into place, these primitives. And then as a bonus, we will be doing something that even FreeCAD hasn't figured out over the past, you know, decade or whatever. So we'll be one up on FreeCAD in 20 minutes or so. So, what did I do so far? So first thing, I broke apart our old main.c file into like a bunch of different sub files. We have all the draw routines are in draw. We have all the genetic routines are in the geometry.hgeometry.c We have what the trigonometry stuff is in the trig. So everything's sort of broken up and then we have a new make routine. So the compilation is just a asterisk.c with the same parameters here. So it's not too different. It just broke into different pieces. Hopefully that'll be easier to follow once this project grows. I personally hate doing that. I think everything should just be in in one file, but whatever, I'll do it for the for the common good. So what's today's objective? Well, I mentioned last time these constructive solid geometry is the CSG. So what is a CSG? Basically, it's the main operation that you'll use when you in most of the time you do CAD. So let's say you wanted to make a washer. Washer looks like this. A very artist as you know by this point and you might make that washer by taking a large cylinder and subtracting a small cylinder, right? So that's the idea of CSG. You might say the cylinder has radius six. This one has radius one subtraction and you get a nice washer like this. Simple stuff. Now it may not just be you know with very simple things like cylinders maybe you'd want to draw a sketch. Maybe you make some kind of I don't know a clip like we did in the last video. Clip thing. Extrude that and maybe put some holes in there or something you know. There's different things you can do obviously with this with this algorithm and you can look up different things you can do. There's obviously there's unions, differences, intersections, so some of the basic operations that you can deal with a CSG. So for us, I think we start with the most simple of all these primitives and that's going to be a cube. I guess not even a cube more like just a prism a little more general than that. So I have this prism drawn here with the origin at the bottom left eight nodes. And then I have different side lengths. So four in the x direction five in the y direction and three in the z direction. Just to give us some variety in this so it's not all monotonous zeros and ones. So what is the first task here? So I should say let's just run the portal last time so you know what we had. We had this clip thing. It's a pretty nice clip. At this point we will need to do something for geometries. So let's open up the geometry header and make some space. So we'll need a couple of different things. Basically for you know the way I want to encode this in the way most of the time cat encodes the geometry is you have a body and then on that body you have a bunch of faces and each face it'll have edges right it'll have edges it'll have nodes bunch of nodes bunch of edges and of course these don't these edges are also part of the body. So it's just some really chaotic looking tree structure like this and it gets like to be pretty messy. And so the best way I think to it to go ahead and you know coating this up is with linked lists. And so you'll have a linked list for the body faces. So basically you'll have a pointer to the first face which will have a pointer to the next face and pointer to the next face. And you'll have some nodes the same thing. You have a linked list of nodes and maybe edges you'll have linked to the edges as well. And then one more thing is that obviously each each face has edges and nodes. And so what I think we'll do is we'll have an array inside the face. We'll have an array with pointers to the nodes. More edges you know. And we'll have a also we'll have a value in here for the number of elements the number of nodes per face. Anyway this all makes sense once we cut it up. So let's let's go ahead. So first we'll need structure for the nodes for a node. What do you have to encode? Well node is the most elementary of all you know elements in CAD. It's just a single point in space right so this is where you're actually going to be encoding you know the location. I have a x y and a z so we'll have a float x float y float z. And then of course you know in linked list you have to have a pointer to the next node like that. And obviously if you wanted to you could encode I don't know like an orientation or something or maybe you wanted to encode an ID for the node. You might do that later when you want to go ahead and masking stuff but for the time being we'll just stick to the bare minimum. We'll need a similar type of structure for edges. We'll say strut edge next int. Now here's where I said before we're going to have an array of the number of nodes that are going to be part of each edge. And by the way we might actually not do anything with edges in this video just for completeness sake. We'll say int num nodes and we'll say struct node array. And by the way in C structures you could have a node dimension for your last element here in the structure. This last one there's only one you could have a sort of an infinite size to that structure as long as you can account for that. As long as you know the size you can account for that. Now we'll need a very very similar one for faces. It's pretty much exactly the same thing just popping out the word edge for the word face. Yeah that should be good. I forgot a bunch of semicolons. And then lastly you need one for the body. So let's say struct body. And now here's where we have the pointers to everything. So we'll say struct node node. It's going to be the pointer to the first node. We'll have struct edge. It's the pointer to the first edge and we'll have struct face pointer to the first face. And of course you might have an ID value here and inside face you might want to put like an edge array. Obviously many more things can be done here than what we have. But we'll focus on this for now. And now I'm going to just do something a little bit of head of schedule here. And let's write some declarations for some functions we're going to need. And we'll come back and we'll populate these in a minute. So what functions will we need? Well we will need a function that... Just like here we have make clip. We'll need one that makes a rectangular prism. But it won't be a void function. It'll be a function that returns a pointer to that body. So we'll say struct body. We'll say make rectangular prism. This will be our very first primitive. And we'll pass in a couple things. What should we pass in? Just I guess some basic geometric parameters. So we'll say float x0, float y0, float z0. And then I guess length, width and height. Float l, float w, float h. And those we kind of already described in our picture here. So next we'll need some functions that create... I guess just for this time being we'll just do nodes and faces. We won't do anything to do with edges for the time being. So we'll have a make node. We'll have a make face function. And I guess we'll figure out the parameters for that in a minute or so. And I guess we'll do the rest of this later. But this is just the basics of what we'll need. Now in the actual functions for these things here, we can do a little bit more work. So let's start off first with these two functions. I just talked about make node and make face. So what you want to make a node like a linked list, for example, we'll have to pass in a few things of interest here. We'll first pass in the node that we're going to be trying to populate structure values for, as well as the values x, y and z, those are part of the structure. And we'll probably want to give it the next element as well. So this is a very simple function here. We're just going to literally just populate the structure. So we'll say node x equals x, y and z are y and z. And then node next equals next. Simple stuff. Now for a face. It will be a little bit more difficult. Let's see, make face. We'll pass in again. We'll pass in a pointer to the face. We'll pass in all the different parameters we need. So we need int, num nodes, struct for the node array. And I guess the next face is all we have in there. Right struct, face, hastress, next. Now to make a face, the hardest thing for us is just going to be, well obviously we can just say very simply face, num nodes equals num nodes. And then face, next equals next. It's going to be a little more challenging for us to populate that node array here. But nothing more than just a loop. So for int i equals 0, we'll iterate over the number of nodes. So i less than num nodes. And we'll just populate the node array. So let's make this look neat. So we're just copying the values from the node array as an input parameter to this function into the actual structure itself. So it's pretty straightforward. I'll go back and I'll add this to the header file in a second. The next function that we already added our header for, our declaration for is the actual, the make rectangular prism. So I'm going to put up some of this really quick and I'll get back to you to show what I did. Okay, so I just created that function with the bare minimum stuff. So I've basically just mallocked the body for the prism and then eight nodes and six faces, just like you would have on a cube, right? And so at this point it's super, super easy. Now that we've mallocked everything, and obviously you could probably do this in some kind of a loop, but just for the time being let's keep it simple. So we're just going to make nodes. Make node, node one. And the reason why we're defining them outside is because we want to be able to use these nodes in these faces as well as inside any edges that we end up defining in the future, right? So that's why we have to have all these things available to us. We can't just kind of do it all in functions like that. So we'll say node one. The coordinates for node one are going to be x0, y0, z0. We're passing these values in as the parameters for this function. And we'll say the next node is going to be node two. So the link list will be node one to node two. Is that eight? Is that eight? And so we'll define node two, node three, node four, node five, node six, node seven, node eight. Node eight will point to null. Then the rest of them will point to the next one. So eight, seven, six, five, four, three, two. And now, obviously, we're not all going to be at the same spot in space. So we'll say the first one is at x0, x0 plus l. Then we'll say plus l plus w. We'll just say plus w. And the same thing, just all at z plus h. Sorry if we're going so quickly, but I want to get to more than just this. And that should be good. If I mess it up, I guess we'll never find out. I'm not going to check. Then the faces, again, the same thing. Obviously for faces that you have more than just to worry about the size of the structure itself, but you have a question as to how many nodes. And so for ours, in the node array, for example, if you remember we had our structure had a node array with some number of pointers to different nodes. And for us, these faces we have here only have four nodes on them. If you had some kind of pentagonal prison, there'd be five nodes, and this would have to be a five. A triangular prison would have to be a three. So whatever your face number of node count is, it's going to be this value here. So at this point, we can start populating the faces. So for that, we'll use the make face function. But as a parameter, remember we have that node array. So we'll have to create that first outside. So let's define some kind of temporary variable we can use for this. We'll say struct node star node array four, size four. And then we'll just use that over and over and over again for each different call to make face. So we'll say node array zero equals node one. So let's do the first face here. Let's do one, two, three, four just to keep it easy. So we'll say node one. Then the second element is going to be node two. Third is node three, fourth is node four. And then we'll call make face with this. So we'll say make face, face one. If there's a number of nodes, it's four. Then the node array and then face two. So it'll be a pointer, a link list from face one to face two to face three. And I'll go ahead and I'll populate this really quick for all the different faces and I'll get back to you. Okay, I just quickly put in make faces for all the faces. So face one, two, three, four, five and six. At this point we've created faces in terms of a link list. And now you just have to put those values into the body, which is a prism if you remember. So we'll say prism node equals node one. The first node is the first node. And then prism face equals face one. And at that point we're done. We've literally created a r-primitive array like that. It doesn't look very pretty. It's like 30, 40 lines, but whatever, it gets the job done. So now before I do anything else, let's actually make something that we can view our results because we want to be able to see this in action. And if we just run it, we're not going to see anything. So let's create some functions here that we can use to see if our model isn't working. So let's make one function that just prints the elements of the body. So print body elements. And let's make one function. And this is the bonus I said in the beginning. In FreeCAD, last time I checked and one of the biggest problems in FreeCAD that a lot of other CAD tools solve is that you don't have a way to pick points in space. Like the naming scheme in FreeCAD, you know, you'll have like vertex three or something. And vertex three is not always going to be vertex three if you fundamentally change the geometry, right? So the naming scheme doesn't work. If you look on their DOM forums, they just say, oh, run the GUI and figure out the name and the code. It doesn't work if you do everything from the command line. So yeah, it sucks to suck for FreeCAD. Other tools like advocates and stuff, like you have routines that you can literally pick points in space. Like I can say find at or find closest or something, you know. So the closest node to a certain point. I can query that with a function and get a pointer to that. So it's just infinitely better. FreeCAD literally sucks, but our code will not suck. As a video six, we will be better than FreeCAD. So the next function I want to do is not a void function. It will be a pointer to the node, but we'll have a get closest node. That's a really big deal to me. Like if the CAD tool can't do that, it's not even really a CAD tool. So yeah, so let's go this up. This should be pretty simple. So print elements. So what I want to do for print elements, I want to pass in obviously a body, so we'll say struct, body, body. And then we will iterate over the faces and then over the nodes inside the face. And we'll just print everything out. So let's start simple. Let's say in I equals zero, we'll define a face, iterator here. So face, iter equals the very first face in the body. And then we will iterate through. So we'll iterate through link list. You just say while the iterator is not null. So while you're not at the end of the list, we'll print our face. So we're iterating through faces. So we'll say print face number percent D. And that will just be I. And we'll iterate inside here as well. And I will do a for loop. So we'll say for int j equals zero, j less than iter num nodes. So we'll do the number of nodes in that face. Increment that. And then we're just going to print F. Well, I guess we'll do a tab here. We'll say node number. We'll even have a number. I guess we will. We'll say percent D. And then we'll give it some coordinates. So we'll say percent F, percent F, percent F, slash N. And we'll pass in these values. So we'll say j, then iter node array j x, then iter node array j y, and iter node array j b. That should work. And then outside that four, we'll have to set the iterator next. So we'll say iter equals iter next. We'll return. So this should print out all the faces and nodes on our body. We'll iterate the faces and then the nodes and then print it all out. And I'll get closest node. This is my favorite thing, as you can already tell. So we'll say we'll give it the same body. So we'll search across the entire body. And we'll search for a node at coordinates x0, y0, z0. Okay, this one might be a little more complicated. So we'll need a couple of different things. We'll need a closest node that we'll keep track of, you know, iterating through. We'll see which one is the closest as we go around all the nodes to our certain point. And we'll start off with defining that as the first node. We'll create an iterator again here. So iter equals body node next. I could just put closest dot next, right? Then we'll say float demand. So the minimum distance we need to value to keep track of how far each node is from the node that we're searching for. And we'll just say it's just the power of something, comma, 0.5. It's the sum of the squares to find distance. So it's a power iter. I guess we'll be closest. x minus x0, comma, 2, plus, pal, closest, y minus y0, comma, 2, plus, pal, closest, z minus z0, comma, 2. And then we'll define the value just to keep track of that later. Now that's where a similar to one before we just say, we'll iterate through your source a while, you know. We'll go through every single one of these nodes that we're checking to see if it's closest to the point of interest, x0, y0, z0. So we'll say, well, it's not equal null as we did before. And so we'll have to calculate d. So the same equation is this. The only difference for d is it's not going to say dmin, obviously. It's not going to have a flow in front also. It's not going to say closest. It'll say iter. So iter x, iter y, iter z. Then we'll say if d less than dmin, we'll say dmin equals d and then closest equals iter. So if we have the lowest distance out of everything so far, we'll save the value and we'll save the distance. And then outside that loop, we'll just have to increment our iterator. Equals iter next. And then we will return the closest. So that's literally the entire body of code for this. I will go through, I'll add these to the header file and I'll create something in the main function. And yeah, we'll go ahead with this. I'll have a function that calls all these things in a line and I'll let you know how that goes. Okay, so now we're in the main function here. I just created that call makeRetangularPrism and then I passed in x0, y0, z0, lwh just as we had in the picture here. These are values. Now the question is how can we use this other routine? It's just to see everything working. So we'll do first, we'll say print body elements and we'll pass in prism. This should just print out everything. Let's run it right now and see. It compiles, that's good. So here we go. We're iterating through every single face and then all the nodes that are stored in the array for that face. So node 0 through 3. Now this is not the global ID. We didn't give a global ID. So we'd have to say int id then give a value for that which we will later for the time being we don't need that. And so we have the coordinates here x, y, z for all the different points. And I think we have half of them are at z equals 3 so that looks to be right to me. So yeah, this is it. So we've actually encoded a model just like we had attended to a body, faces, and nodes. So the next question is can we use our get closest node function? That's going to be the ultimate test. So we'll call that function, we'll say favorite node equals get closest node in body prism. We'll pick a node that's somewhere on this model or close. We'll say 4.01, 0.01, 3.1. Something close to 403, so 403. So node 6 should come up. It won't be called node 6 but it should be at 403. And then let's print it out. Let's say print my favorite node is close to 4.01, 0.01, 3.1. And it's percent f, percent f, percent f. And we'll pass in what I call it favorite node. Favorite node, x, favorite node, y, favorite node. Let's see, this better work. It all looks so done. Oops, what'd I do? Did I mess up something? Oh, x, y, and z. What? Oh, I didn't put this stupid greater than sign. Oops. Yeah, so my favorite node, if you can see this, is close to this. And it's this. So we come up with a functionality which far exceeds that of FreeCAD. So you can applaud yourself and myself in this wonderful accomplishment here. So yeah, that's it for this video. We did the very basics, the fundamentals of CSG. In the next video, we will do a little bit more. Obviously, we can't visualize this because these faces have four nodes per face. And if you recall, I mean, the code that we wrote in our draw routine, this works with triangles. You know, we only have three triangles. We're doing, you know, this thing here, we're working with triangles. So three is not going to work for us. Four is not going to work for us. Three will work. So we have to break these up into three and we'll do it in a more generic way because how will we know if we're going to have four nodes per face or five or six or seven? There's an algorithm that I'm going to teach you guys about that we'll be able to break apart any face into triangles. And that's pretty cool. So stay tuned for that. Anyway, thanks for watching.