You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@josefinelissner and I are working on some examples how to use PicoGK.
In the meantime, I'd like to point out the few basic PicoGK examples available in the Examples subdirectory. If you followed the steps in the ReadMe, you should be able to test them out.
I'd like to walk you through the Implicits example, just because that's what currently many people do expect to do when they design for Additive.
namespacePicoGKExamples{///////////////////////////////////////////////////////////////////////////// Below is a static class that implements a single static function// that can be called from Library::Go()classImplicitsExample{
This encapsulates everything we do in the namespace PicoGKExamples and then in a class called ImplicitsExample.
The class ImplicitsExample implements a few classes inside that we are going to use, and just one static function (a function that doesn't require an instance of the class to be created), called "Task". Task is what you will pass to Library.Go in your Program.cs.
Let's look at the classes in the example:
publicclassImplicitGyroid:IImplicit{
....
}
and
publicclassImplicitLattice:IImplicit{
....
}
These are two classes which implement the interface IImplicit. An interface in C# is like a contract. If you implement an interface, your class needs to implement a certain set of functions, otherwise your program will not compile. In the case of IImplicit, this is just one function:
publicinterfaceIImplicit{/// <summary>/// Return the signed distance to the iso surface/// </summary>/// <param name="vec">Real world point to sample</param>/// <returns>/// Distance to the Iso surface in real world values/// 0.0 is at the surface/// Negative values indicate the inside of the object/// Positive values indicate the outside of the object/// </returns>publicabstractfloatfSignedDistance(inVector3vec);}
So, any class derived from IImplict needs to implement the function fSignedDistance, which gets a position in space (in mm) as input, and returns the distance (in mm) to the surface of the object you are describing. If you are inside the object, the distance is negative, if you are outside the object, the distance is positive, and if you are exactly on the surface, the distance is zero.
In our code, we implement a class for Gyroids, which you can see in the code. This is mostly boilerplate code (you can use ChatGPT to generate a lot of these, by telling it to create C# code for a signed distance function for certain objects).
First we implement a constructor for our class, this is the function that is called, when you instantiate the ImplicitGyroid class with new. What we do in the constructor is simply store the parameters that we are going to use when we calculate the signed distance.
So, we calculate a scale (which is just constant, so we could have done it in the function itself), we have a unit size in mm (which is how big each Gyroid cell is) and we have a wall thickness in mm, which we all store in member variables of the class for later use.
publicfloatfSignedDistance(inVector3vecPt){// Calculate the normalized coordinates within the gyroid spacedoublenx=vecPt.X/m_fUnitSize;doubleny=vecPt.Y/m_fUnitSize;doublenz=vecPt.Z/m_fUnitSize;// Calculate the gyroid surface equationdoublefDist=Math.Sin(m_fScale*nx)*Math.Cos(m_fScale*ny)+Math.Sin(m_fScale*ny)*Math.Cos(m_fScale*nz)+Math.Sin(m_fScale*nz)*Math.Cos(m_fScale*nx);// Apply thickness to the gyroid surfacereturn(float)(Math.Abs(fDist)-0.5f*m_fWallThickness);}
Now we implement the actual signed distance function, which uses the parameters we stored. If queried about the signed distance to the gyroid for any point in space, it returns the value from the function.
The next class is the implicit lattice class. I won't go into the detail, as it's basically the same concept, just for a lattice. PicoGK implements its own native lattices, but in order to understand how lattices actually work (they are made up of implicit primitives), I have included this function.
Let's look at how we actually use these classes.
Let's look at the Task static function that we will call from PicoGK.Library.Go:
The first thing we do is encapsulate everything in a try {} catch {} block. PicoGK uses Exceptions when an error occurs and by "trying" a block of code and "catching" the exception when something goes wrong, we can print out a meaningful message what happened.
The next thing is, just for fun, we set the color of our default material to a fashionable red (and use a dull, non-metallic material).
Now we store the values that we are using in the implicit lattice in a new lattice object.
// Let's instantiate one implicit lattice, and store the parameters// which will be used in the signed distance functionImplicitLatticeoLattice=newImplicitLattice(newVector3(0f,0f,0f),newVector3(0f,0f,50f),5.0f,10.0f,true);
Now, let us create a new voxel field, and render the lattice into it. Note, a signed distance function has no "boundaries" — theoretically you can call it for any point in space. So, when we create a new voxel field, we have to tell the voxel field constructor, which area in space to actually evaluate. It will then run a loop over all three dimensions in space in the box specified, and call our signed distance function to determine whether we are inside, outside, or on the surface of the object. We implemented a bounding box calculation in our lattice, so we are passing this box.
// Create a new voxel field, which renders the lattice// we are passing the bounding box of the lattice, so that// we know which area in the voxel field to evaluateVoxelsvoxL=new(oLattice,oLattice.oBB);
And there you have it, a voxel field, that contains solid voxels (or more accurately, a sparse, discretized signed distance field that contains signed distance values) wherever the lattice is.
All we have to do, is add it to the viewer to see it:
// Let's show what we gotLibrary.oViewer().Add(voxL);
I will not go over the rest of the code in detail. The next lines create a Gyroid in a voxel field (since a gyroid has no bounds, we pass an explicit bounding box).
For fun, we extract one slice of it as a grayscale image (TGA) file and a color-coded signed distance field color image file.
In the last example, we create another lattice, and then intersect it with the Gyroid function. Using Voxels.IntersectImplicit, you can create infill patterns in other objects. What you usually do is create an offsetted smaller second voxel field, subtract it from the previous one to create a shell, then you intersect the small one with an implicit (say a gyroid), and then add both together. You now have an object with a gyroid infill.
Here is the output of the code (below is your Program.cs code)
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Dear All,
@josefinelissner and I are working on some examples how to use PicoGK.
In the meantime, I'd like to point out the few basic PicoGK examples available in the Examples subdirectory. If you followed the steps in the ReadMe, you should be able to test them out.
I'd like to walk you through the Implicits example, just because that's what currently many people do expect to do when they design for Additive.
Check out the ImplicitsExample here.
Let's walk through what the code does.
This encapsulates everything we do in the namespace PicoGKExamples and then in a class called ImplicitsExample.
The class ImplicitsExample implements a few classes inside that we are going to use, and just one static function (a function that doesn't require an instance of the class to be created), called "Task". Task is what you will pass to Library.Go in your Program.cs.
Let's look at the classes in the example:
and
These are two classes which implement the interface IImplicit. An interface in C# is like a contract. If you implement an interface, your class needs to implement a certain set of functions, otherwise your program will not compile. In the case of IImplicit, this is just one function:
So, any class derived from IImplict needs to implement the function fSignedDistance, which gets a position in space (in mm) as input, and returns the distance (in mm) to the surface of the object you are describing. If you are inside the object, the distance is negative, if you are outside the object, the distance is positive, and if you are exactly on the surface, the distance is zero.
This is how you describe so-called implicits, one of the most famous formulas used in implicit modeling is the gyroid (which you have seen maybe too often). Check out my article on implicits that I wrote in my series on the Fundamentals of Computational Engineering.
In our code, we implement a class for Gyroids, which you can see in the code. This is mostly boilerplate code (you can use ChatGPT to generate a lot of these, by telling it to create C# code for a signed distance function for certain objects).
First we implement a constructor for our class, this is the function that is called, when you instantiate the ImplicitGyroid class with new. What we do in the constructor is simply store the parameters that we are going to use when we calculate the signed distance.
So, we calculate a scale (which is just constant, so we could have done it in the function itself), we have a unit size in mm (which is how big each Gyroid cell is) and we have a wall thickness in mm, which we all store in member variables of the class for later use.
Now we implement the actual signed distance function, which uses the parameters we stored. If queried about the signed distance to the gyroid for any point in space, it returns the value from the function.
The next class is the implicit lattice class. I won't go into the detail, as it's basically the same concept, just for a lattice. PicoGK implements its own native lattices, but in order to understand how lattices actually work (they are made up of implicit primitives), I have included this function.
Let's look at how we actually use these classes.
Let's look at the Task static function that we will call from PicoGK.Library.Go:
The first thing we do is encapsulate everything in a try {} catch {} block. PicoGK uses Exceptions when an error occurs and by "trying" a block of code and "catching" the exception when something goes wrong, we can print out a meaningful message what happened.
The next thing is, just for fun, we set the color of our default material to a fashionable red (and use a dull, non-metallic material).
Now we store the values that we are using in the implicit lattice in a new lattice object.
Now, let us create a new voxel field, and render the lattice into it. Note, a signed distance function has no "boundaries" — theoretically you can call it for any point in space. So, when we create a new voxel field, we have to tell the voxel field constructor, which area in space to actually evaluate. It will then run a loop over all three dimensions in space in the box specified, and call our signed distance function to determine whether we are inside, outside, or on the surface of the object. We implemented a bounding box calculation in our lattice, so we are passing this box.
And there you have it, a voxel field, that contains solid voxels (or more accurately, a sparse, discretized signed distance field that contains signed distance values) wherever the lattice is.
All we have to do, is add it to the viewer to see it:
I will not go over the rest of the code in detail. The next lines create a Gyroid in a voxel field (since a gyroid has no bounds, we pass an explicit bounding box).
For fun, we extract one slice of it as a grayscale image (TGA) file and a color-coded signed distance field color image file.
In the last example, we create another lattice, and then intersect it with the Gyroid function. Using Voxels.IntersectImplicit, you can create infill patterns in other objects. What you usually do is create an offsetted smaller second voxel field, subtract it from the previous one to create a shell, then you intersect the small one with an implicit (say a gyroid), and then add both together. You now have an object with a gyroid infill.
Here is the output of the code (below is your Program.cs code)
OK, so this is a small run-through the absolute basics of creating something that is quite common in Design for Additive.
Let me know if this makes sense, and drop a question below if it doesn't.
Lin
Beta Was this translation helpful? Give feedback.
All reactions