Build a Two Part Mold

In this tutorial we will build a two part mold of a high-rise building massing model for casting. The key point of interest is performing Brep/Solid Boolean operations, unions, subtraction, splitting, using programming, to create complex solid models.

mold

Technique

  1. Create a solid mold block by creating and converting a generic axis aligned bounding box into a solid.
  2. Create (or import) one or more solids that represent the building’s massing model and Boolean union multiple solids into one mass (optional).
  3. Create cylindrical registration dowels that run across the mold block perpendicular to the slicing direction.
  4. Subtract the massing model, one or more parts, and registration dowels from the mold solid.
  5. Split the mold block into two parts and emit the two volumes.

Procedure

private void RunScript(double DeltaX, double DeltaY, double DeltaZ, 
    ref object Geometry)
  {

    //--------------------------------------------------------------------------------
    //-- SOP
    //--
    Print("Started"); 
    var geometry = new List<object>();



    //--------------------------------------------------------------------------------
    //-- Build The Mould Block
    //--

    Brep mold = Brep.CreateFromBox(new BoundingBox(0, 0, 0, DeltaX, DeltaY, DeltaZ));

    ///geometry.Add(mold);

    Print("Mold Block Created");



    //--------------------------------------------------------------------------------
    //-- Build The Massing Blocks
    //--

    Brep blk1 = Brep.CreateFromBox(new BoundingBox(15, 15, 0, 50, 75, 180));
    Brep blk2 = Brep.CreateFromBox(new BoundingBox(40, 35, 0, 80, 90, 250));

    ///geometry.Add(blk1);
    ///geometry.Add(blk2);


    Print("Massing Blocks Created");


    //--------------------------------------------------------------------------------
    //-- Build Union of 2x Massing Blocks
    //-- 1. Group solids into a list or array (using array below)
    //-- 2. Ask Rhino to Union and store the results
    //-- 3. Select the first solid of union
    //--
    //--    Notice: that in general a Boolean Union may produce
    //--    multiple solids (or it may fail). So this is why
    //--    Rhino gives back an array of solids instead of one!
    //--

    Brep[] parts = new Brep[]{blk1, blk2};
    Brep[] whole = Brep.CreateBooleanUnion(parts, 0.0001);

    if( whole.Length != 1 )
    {
      Print("Boolean Union Failed, Bye!");
      return;
    }

    Brep union = whole[0];
    ///geometry.Add(union);


    Print("Massing Blocks Joined");


    //--------------------------------------------------------------------------------
    //-- Create the Registration Dowels
    //-- Need some params, define locally but you can import
    //-- from grasshopper context as we do for DeltaX etc
    //--

    var margin = 4;               //-- From the wall edge
    var radius = 4;               //-- Of each dowel
    var height = DeltaZ;          //-- All the way
    var capped = true;            //-- Make capped cylinder aka solid

    //-- Collection of dowels
    //--
    var dowels = new List<Brep>();

    //-- Quite wildly nested expression...
    //--
    //-- 1. To Make Solid Cylinder     -> We need a Cylinder Surface
    //-- 2. To Make a Cylinder Surface -> We need a Circle and a Height
    //-- 3. To Make a Circle           -> We need a Plane and a Radius
    //-- 4. To Make a Plane            -> We need a Centre Point
    //--
    dowels.Add(Brep.CreateFromCylinder(new Cylinder(new Circle(new Plane(
      new Point3d(margin + radius, margin + radius, 0), 
      Vector3d.ZAxis), radius), height), capped, capped));

    //-- Step by Step
    //--
    //-- We would had to do the same steps with nodes in grasshopper and connect the cables
    //-- Notice this position of the hole is registered from the right edge of the box (not as above)
    //--
    Point3d center = new Point3d(DeltaX - margin - radius, margin + radius, 0);
    Plane basis = new Plane(center, Vector3d.ZAxis);
    Circle profile = new Circle(basis, radius);
    Cylinder surface = new Cylinder(profile, height);
    Brep dowel = Brep.CreateFromCylinder(surface, capped, capped);
    dowels.Add(dowel);

    //-- This is better... Make a function as seen below and reuse
    //-- Looks simpler and semantically cleaner
    //--
    dowels.Add(CreateDowel(margin + radius, DeltaY - margin - radius, radius, height));
    dowels.Add(CreateDowel(DeltaX - margin - radius, 
      DeltaY - margin - radius, radius, height));

    ///geometry.AddRange(dowels);


    Print("Registration Dowels Created");






    //--------------------------------------------------------------------------------
    //-- Remove the parts from the mold block
    //--
    //-- Note: Wrapping the mold into a collection of one item is a perculiarity
    //-- of Rhino, but it makes sense if you want to remove many from many objects
    //--

    var mold_whole = new List<Brep>();
    mold_whole.Add(mold);

    var mold_pars = new List<Brep>();
    mold_pars.Add(union);
    mold_pars.AddRange(dowels);

    Brep[] complete_mold = Brep.CreateBooleanDifference(mold_whole, mold_pars, 0.00001);

    if( complete_mold.Length != 1 )
    {
      Print("Failed to Subtract Mold, Bye!");
      return;
    }

    Brep one_part_mold = complete_mold[0];
    ///geometry.Add(one_part_mold);


    Print("Single Part Mold Created");



    //--------------------------------------------------------------------------------
    //-- Chop The Mold into 2x Parts
    //--
    //-- Building two half-blocks to remove from one_part_mold
    //--

    Brep chop_lt = Brep.CreateFromBox(new BoundingBox(0, 0, 0, DeltaX, DeltaY / 2, DeltaZ));
    Brep chop_rt = Brep.CreateFromBox(new BoundingBox(0, DeltaY / 2, 0, DeltaX, DeltaY, DeltaZ));

    ///geometry.Add(chop_lt);
    ///geometry.Add(chop_rt);


    Brep mold_lt = Chop(one_part_mold, chop_lt);
    Brep mold_rt = Chop(one_part_mold, chop_rt);

    if( mold_lt == null || mold_rt == null )
    {
      Print("Chopping Failed, Bye!");
      return;
    }

    geometry.Add(mold_lt);
    geometry.Add(mold_rt);


    Print("Two Part Mold Created");


    Geometry = geometry;

    Print("Completed");

  }

  // <Custom additional code> 


  Brep Chop(Brep mold, Brep cutter)
  {
    //-- Using a short hand notation where
    //-- we package the single solids into
    //-- arrays (because Rhino wants)
    //--
    Brep[] result = Brep.CreateBooleanDifference(
      new Brep[]{mold},
      new Brep[]{cutter}, 0.0001);

    //-- By convention if the operation fails
    //-- ie. the result is not a single solid
    //-- we give back a null value as indication
    //-- of problems
    //--
    if( result.Length != 1 ) return null;
    return result[0];
  }


  Brep CreateDowel(double x, double y, double r, double h)
  {
    //-- Same above really
    //--
    Point3d center = new Point3d(x, y, 0);
    Plane basis = new Plane(center, Vector3d.ZAxis);
    Circle profile = new Circle(basis, r);
    Cylinder surface = new Cylinder(profile, h);
    return Brep.CreateFromCylinder(surface, true, true);
  }


  // </Custom additional code> 

 

Remarks

  1. This approach to generating massing models is not quite useful unless the design concept/scheme is very clear.
  2. Boolean operations are rather slow, take significant computing power and don’t run in fluid parametric sketching mode. They are rather fragile, prone to numerical errors, topological changes and generally failures.
  3. In conclusion, operating on solid models with Boolean operations is rather counter-intuitive via code. Perhaps applications such as Solidworks/CATIA etc are more appropriate for this kind of modeling process.