ShapeKernel Geometry Library

repository·main·Indexed 42 days ago

https://github.com/leap71/leap71_shapekernel

A geometry library that bridges low-level PicoGK kernel operations with high-level engineering functions to generate complex geometric primitives called BaseShapes. It supports the creation of geometries using Voxels, Lattices, and Implicits (SDFs), and provides tools for Local Frames, spined shapes, and line/surface modulations for computational engineering.

Tokens
5.4K
Snippets
9
Records
16
Agent score
54%

What's inside ShapeKernel

  1. Overview of ShapeKernel and the Computational Engineering Stack

    main

    ShapeKernel is a library designed to bridge low-level geometry kernel operations (specifically using the PicoGK engine) with high-level engineering functions. It is used to generate geometric primitives known as BaseShapes, which act as the fundamental building blocks for complex engineering designs.

    In the ShapeKernel workflow, complex objects (like a heat exchanger) are constructed by logically and spatially combining hundreds of these BaseShapes using Boolean() and Offset() operations.

    ShapeKernel sits at the third layer of the software stack, supporting the Computational Engineering Models (CEMs) layer, which contains the algorithms and engineering knowledge required to generate specific types of objects.

  2. Use Frames to create spined shapes

    main

    While a Local Frame defines a single coordinate system, Frames are sequences of local frames distributed along a spline. Frames are used to construct "spined" Base Shapes (like pipes) that evolve or twist along a path.

    In a sequence of Frames:

    • The local z axis runs tangentially to the spline.
    • The local x and y axes lie in a plane perpendicular to the spline.

    Frame Targeting Strategies

    Frames can be oriented using different strategies:

    • Constant Target: Local x axes are rotated to maximize alignment with a specific target vector (e.g., Vector3.UnitY).
    • Cylindrical (Radially-targeted): Frames target a radial or spherical direction, which is useful for objects with rotational symmetry like motors or rocket chambers.

    Working with Frames

    You can create Frames from a spline or a constant Local Frame and query a specific frame at a given point along the spine using a length ratio.

    ISpline oSpline = new BasicSpline();
    Frames aFrames  = new Frames(oSpline.aGetPoints(), Vector3.UnitY);
    
    // Create radially-targeted Frames from a spline
    Frames aFrames = new Frames(oSpline.aGetPoints(), Frames.EFrameType.CYLINDRICAL);
    
    // Create Frames along a straight line with constant target directions
    LocalFrame oConstFrame = new LocalFrame(
      new Vector3(10, 30, 30), 
      new Vector3(0, 1, 0), 
      new Vector3(0, 0, 1));
    Frames aFrames = new Frames(100, oConstFrame);
    
    // Query a Local Frame along the spine length (0.0 to 1.0)
    float fLengthRatio = 0.2f;
    LocalFrame oFrame = aFrames.oGetLocalFrame(fLengthRatio);
  3. Create geometries using Voxels

    main

    Voxels represent a digital material distribution within a regular 3D grid (a voxel field). In ShapeKernel, you do not typically set individual voxels manually; instead, you "voxelize" other geometry types (like Lattices or Implicits) into a voxel field.

    Voxels are the primary output format for many operations and are used to derive final outputs such as STL files, G-code, or image files. Common operations performed on voxels include voxBoolean(), voxOffset(), and voxSmoothen().

  4. Understand ShapeKernel nomenclature and naming conventions

    main

    ShapeKernel uses a prefix-based naming convention to indicate the data type of variables and objects. This improves readability and helps developers identify object types at a glance.

    Variable Prefixes

    • Floating point: f (e.g., float fValue)
    • Double precision: d (e.g., double dVolume)
    • Integers: i (e.g., int iCounter)
    • Unsigned Integers: n (e.g., uint nSamples)
    • Vectors: vec (e.g., Vector3 vecPt)
    • Lists / Arrays: a (e.g., List<Vector3> aPoints)
    • Structs: s (e.g., SProfile sProfile)
    • Interfaces: x (e.g., ISpline xSpline)
    • Other Objects: o (e.g., InjectorElement oSwirler)

    Member Variables

    • Class member variables are prefixed with m_ (e.g., float m_fMass).

    Geometry Type Prefixes

    • Lattices: Generic context uses oLattice; specific context uses lat (e.g., Lattice latPipes).
    • Implicits: Generic context uses oImplicit; specific context uses sdf (e.g., IImplicit sdfSphere).
    • Voxels: Generic context uses oVoxels; specific context uses vox (e.g., Voxels voxMotor).

    Function names follow the same pattern based on their return type (e.g., voxUnion() returns a voxelfield, vecRotate() returns a vector).

  5. Quickstart: Operating a Base Shape

    main

    To create and manipulate a geometry in ShapeKernel, follow these steps:

    1. Instantiate: Create a shape using either a LocalFrame or a set of Frames.
    2. Modulate: Use SetWidth, SetDepth, or SetRadius to apply LineModulation or SurfaceModulation objects.
    3. Transform: Apply a coordinate-based deformation using SetTransformation.
    4. Refine: Adjust surface quality using SetLengthSteps, SetRadialSteps, or SetPolarSteps.
    5. Render: Convert the shape into a voxel field using voxConstruct().
    BaseSphere oShape   = new BaseSphere(oFrame, 10);
    BaseCylinder oShape = new BaseCylinder(oFrame, 50, 30);
    
    // 2. Set Modulations
    oShape.SetWidth(new LineModulation(fGetWidthOverLengthRatio));
    oShape.SetRadius(new SurfaceModulation(oLineModulation));
    
    // 3. Set Transformation
    oShape.SetTransformation(vecGetTransformedPoint);
    
    // 4. Update resolution
    oShape.SetLengthSteps(500);
    
    // 5. Render to voxels
    Voxels oVoxels = oShape.voxConstruct();
  6. Run a ShapeKernel Task using PicoGK.Library.Go

    main

    To execute a ShapeKernel task, you must call PicoGK.Library.Go within your Program.cs. This function serves as the entry point that initializes the PicoGK library and executes the specified task.

    When calling PicoGK.Library.Go, you should provide:

    1. Voxel Size: A float representing the resolution (e.g., 0.1f for 0.1mm). Sensible values typically range between 0.05f and 1.0f.
    2. Task Function: The specific task method from the ShapeKernel library you wish to run (e.g., Leap71.ShapeKernelExamples.BaseLensShowCase.Task).
    3. Output Folder: A string path to a directory where STLs and log files will be saved. Note: This folder must already exist on your computer.
    using PicoGK;
    
    string strOutputFolder = "/Users/youruser/Documents/Examples";
    
    try
    {
        PicoGK.Library.Go(
            0.1f,
            Leap71.ShapeKernelExamples.BaseLensShowCase.Task,
            strOutputFolder
            );
    }
    catch (Exception e)
    {
        Console.WriteLine("Failed to run Task.");
        Console.WriteLine(e.ToString());
    }
  7. Use Local Frames for object placement

    main

    A Local Frame is a coordinate system defined by a position and three orthogonal axes (local x, y, and z). Base Shapes in ShapeKernel are constructed relative to a Local Frame rather than the absolute coordinate system. This allows you to orient and place shapes easily without changing their internal construction logic.

    Creating Local Frames

    • Absolute: A frame identical to the absolute coordinate system.
    • Translated: A frame moved to a specific position.
    • Custom Orientation: A frame with specific local z and/or x directions.

    Querying a Local Frame

    You can retrieve the position and local axes using vecGetPosition(), vecGetLocalX(), vecGetLocalY(), and vecGetLocalZ().

    LocalFrame oFrame = new LocalFrame();
    
    // Instantiate a Local Frame translated against the absolute coordinate system
    LocalFrame oFrame = new LocalFrame(new Vector3(2, 5, -3));
    
    // Instantiate a Local Frame with a custom local z direction
    LocalFrame oFrame = new LocalFrame(new Vector3(2, 5, -3), new Vector3(1, 0, 0));
    
    // Instantiate a Local Frame with custom local z and local x directions
    LocalFrame oFrame = new LocalFrame(new Vector3(2, 5, -3), new Vector3(0, 0, 1), new Vector3(1, 0, 0));
    
    // Query position and directions
    Vector3 vecPos    = oFrame.vecGetPosition();
    Vector3 vecLocalX = oFrame.vecGetLocalX();
    Vector3 vecLocalY = oFrame.vecGetLocalY();
    Vector3 vecLocalZ = oFrame.vecGetLocalZ();
  8. Create geometries using Lattices

    main

    A Lattice is a collection of Nodes and Beams that can be rendered into a voxel field.

    • Nodes: Small spheres defined by a 3D position and a radius.
    • Beams: Conical cylinders connecting two points. Each point has a radius, and the ends can be either rounded or flat-capped.

    To use a Lattice, instantiate it, add nodes or beams, and then render it to a Voxels object.

    Lattice oLattice = new Lattice();
    
    // Add a node
    Vector3 vecPt0 = new Vector3(1, 5, 10);
    float fRadius0 = 10;
    oLattice.AddSphere(vecPt0, fRadius0);
    
    // Add a flat-capped beam
    Vector3 vecPt1 = new Vector3(5, 3, 0);
    float fRadius1 = 3;
    Vector3 vecPt2 = new Vector3(-3, 0, 7);
    float fRadius2 = 5;
    bool bRounded = false;
    oLattice.AddBeam(vecPt1, fRadius1, vecPt2, fRadius2, bRounded);
    
    // Add a rounded beam
    bRounded = true;
    oLattice.AddBeam(vecPt1, fRadius1, vecPt2, fRadius2, bRounded);
    
    // Render lattice into a voxelfield
    Voxels oVoxels = new Voxels(oLattice);
  9. Create geometries using Implicits (SDFs)

    main

    Implicits describe shapes using Signed Distance Functions (SDFs) via the IImplicit interface. An SDF defines the distance from any point in space to the object's surface, with the sign indicating whether the point is inside or outside.

    Implicits are useful for simple shapes and complex infill patterns (like gyroids). Because they can be periodic or unbounded, you must specify a bounding box (BBox3) or a bounding voxel field when rendering them into voxels.

    Custom SDF Implementation

    To create a custom implicit, implement the IImplicit interface and define the fSignedDistance method.

    IImplicit sdfSphere  = new ImplicitSphere(vecCentre, fRadius);
    IImplicit sdfPattern = new ImplicitGyroid(15, 3);
    
    // Render an implicit into a new voxel field using a bounding box
    BBox3 oBBox = new BBox3(
      1.5f * new Vector3(-fRadius, -fRadius, -fRadius), 
      1.5f * new Vector3(fRadius, fRadius, fRadius));
    Voxels voxSphere = new Voxels(sdfSphere, oBBox);
    
    // Intersect a voxelfield with a 3D pattern (infill)
    Voxels voxGyroidSphere = Sh.voxIntersectImplicit(voxSphere, sdfPattern);
    
    // Custom SDF implementation example
    public class ImplicitSphere : IImplicit
    {
      protected Vector3 m_vecCentre;
      protected float m_fRadius;
    
      public ImplicitSphere(Vector3 vecCentre, float fRadius)
      {
        m_vecCentre = vecCentre;
        m_fRadius = fRadius;
      }
    
      public float fSignedDistance(in Vector3 vecPt)
      {
        return (vecPt - m_vecCentre).Length() - m_fRadius;
      }
    }
  10. Include the ShapeKernel library in your Visual Studio project

    main

    You can add the ShapeKernel library to your existing Visual Studio project using one of two methods:

    Beginner Method

    1. Download the ShapeKernel source code as a .zip file from the official releases.
    2. Unzip the file and copy the contents directly into your Visual Studio project folder.

    Pro Method

    Add ShapeKernel as a Git submodule by linking the repository: https://github.com/leap71/LEAP71_ShapeKernel.

  11. Create Surface Modulations

    main

    A Surface Modulation is the 2D equivalent of a Line Modulation. It defines how a dimension (like radius) evolves across two dimensions of a surface (e.g., polar and length dimensions).

    Surface Modulations can be created from:

    1. A constant value.
    2. A 1D functional modulation (derived from a LineModulation).
    3. A 2D functional modulation (a delegate function taking two parameters).

    To query a value, use fGetModulation(fRatio1, fRatio2).

    SurfaceModulation oSurfaceModulation = new SurfaceModulation(5);
    
    // From a 2D function
    public float fGetRadiusOverPhiLengthRatio(float fPhi, float fLengthRatio)
    {
       float fRadius = 30 + 20 * fLengthRatio + 5f * MathF.Cos(6f * fPhi);
       return fRadius;
    }
    SurfaceModulation oSurfaceModulation = new SurfaceModulation(fGetRadiusOverPhiLengthRatio);
    
    // From a Line Modulation
    SurfaceModulation oSurfModulation = new SurfaceModulation(oLineModulation);
    SurfaceModulation oSurfModulation = new SurfaceModulation(oLineModulation, SurfaceModulation.ELine.FIRST);
    SurfaceModulation oSurfModulation = new SurfaceModulation(oLineModulation, SurfaceModulation.ELine.SECOND);
    
    // Querying a value
    float fValue = oSurfaceModulation.fGetModulation(fRatio1, fRatio2);