damogranlabs / classy_blocks

Python classes for easier creation of OpenFOAM's blockMesh dictionaries.
MIT License
129 stars 35 forks source link

enhancement: operations on sketches #43

Open bjnieuwboer opened 1 year ago

bjnieuwboer commented 1 year ago

Hi,

Currently, the operations work only on a single face (or two faces in the loft case). It would be easier to create a blocking structure when these operations work on a sketch, just like in a CAD program. I know it is already possible to do so by using the translation/rotation functions for instance in the elbow shape. However, for an end-user it would be intuitive if the operation classes could by used for this. I understand that this will introduce some work, since a single operation is now converted to a single block.

Would you be willing to take a look at this idea?

FranzBangar commented 1 year ago

This is definitely a thing to consider, I had had it on a TODO list a long time ago, not sure why it's not anymore.

bjnieuwboer commented 1 year ago

Thanks for considering it.

Although I did not mention it explicitly, having users define sketches in an easy manner would definitely help. In making arbitrary sketches I have a difficulty in getting the points in the face in the right order. I've written a script which sorts these points for each face before creating the hex blocks. If you are interested I could post this.

FranzBangar commented 1 year ago

Yes, please do. There is a new ViewpointReorienter object (see tutorial https://github.com/damogranlabs/classy_blocks/blob/development/examples/complex/labyrinth.py) and face.shift() face.reorient() methods but so far all those did not prove their worth in real-life. If there's something you use and it works I'll be happy to add.

bjnieuwboer commented 6 months ago

Hi,

I see you're working on incorporating user defined sketches. I am happy to see that development, since I think it would really enhance the usability. I promised to provide some code on this and on the 3d block array. However, I've been more busy than anticipated and it took me more time.

Now, I've got a working principle with three main classes: 1) quadblocks: the user defined sketches bases on 2d points and connections. The points are automatically sorted. The user does not need to know the order. 2) multi quad blocks: an array of quads (you called it a grid in an example) with t he possibility to add quads based on their locations. For instance add a 5th quad in a 2x2 grid alongside quad (1,1). Also the possibility to delete a quad 3) multi hex blocks: similar to quads, but with a third dimension. Options for selecting vertices based on planes and blocks. Option for translating/rotating/scaling vertices. Option to create a uniform mesh distribution in the multi hex block.

Some thoughts on extensions:

FranzBangar commented 6 months ago

Actually I've just implemented almost all of what you're saying but will need a bit more time to polish everything so that it's ready for publishing. I created a MappedSketch where the user throws in points and connects them using indexes only. I revamped cylinders and added automatic laplacian smoothing.

I'd be happy to see how automatic point sorting is made.

The 'Stacks' are coming next, meaning shapes with multiple elements in the 3rd direction, regardless of what sketch they were created from. So multi-hex block would be an ExtrudedStack where multiple ExtrudedShapes would be stacked one on top of another.

Stay tuned, I'm planning to commit this soon! Then we can compare my ideas with yours and add whatever is missing or off.

bjnieuwboer commented 6 months ago

I am looking forward to this new feature. To address some of the comments you have:

I'd be happy to see how automatic point sorting is made. You can find it in the quadBlocks file. It's the sortQuad and sortClockwise function

The 'Stacks' are coming next, meaning shapes with multiple elements in the 3rd direction, regardless of what sketch they were created from. The upside of an dedicate array structure (multiHex) is the easy indexing of blocks/faces/planes/vertices. That is the reason for implementing the multiHex. In a unstructured stack you cannot as easilly access a block by an index as in a structured stack/multiHex. In that case two different extrudedStacks should be created: one for a structured sketch, which can be index by (i,j,k) corresponding to the block position in each direction. Another one for an unstructured sketch with a (i,j) index corresponding to the inplane index and the index in stack direction.

FranzBangar commented 6 months ago

I have added a 'grid' property to Sketches. So now instead of a flat-list 'faces' property, grid is two-dimensional. For a 'Grid' sketch it is a simple x-y indexing and for cylindrical sketches it's a kind of polar radius-angle index. A Stack, will add a new dimension, that is Shape level, effectively incorporating your proposal seamlessly.

I'll look into your code and let you know.

FranzBangar commented 5 months ago

I checked your code. Almost everything your proposal does should be easily doable within the current feature/stacks branch. The workflow is very similar but machinery underneath not so much.

The paradigm is as before, create a custom sketch and transform it to obtain multiple levels of blocks - a Stack. Each block is accessible with Stack.grid property. It returns a multidimensional list where the first dimension goes along stacked tiers and next are taken further down by shapes and sketches. Any sketch can be stacked.

I added a 'Grid' sketch just for demonstration, it is a totally primitive thing and will be updated soon. There's also another thing that might come in handy, and that is smoothing. If you take a look at examples/shape/custom.py, the rounded block is made by only defining outer points and edges and quad numbering. Smoothing then determines actual sketch contents pretty well. As for 3D block point sorting, there is already an orienter implemented. See https://damogranlabs.com/2023/09/classy_blocks-tutorial-part-5-some-useful-hints/ (but yes, an example should be added ASAP).

You can now remove a block using mesh.delete(), see stack/cube example.

To add a block or anything to the mesh, it's as easy as always, locate an operation (predecessor to a block), find its nearest face (operation.get_closest_face), then do with it whatever you like. Add it to mesh and you're done.

Is there anything else you're missing?