Open8

Script-based CADをLLMと一緒に色々試す

生ビール生ビール

OpenSCAD

https://github.com/openscad/openscad/

公式ドキュメント

https://openscad.org/documentation.html

ここで試せる

https://ochafik.com/openscad2/#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

Claude 3.7-sonnet (think)

下記openscad viewerでのexampleを参考に、ビールジョッキのopenscadを作って。
---
//openSCAD サンプルコード

Output
// Beer Mug Design in OpenSCAD

// Global resolution settings
$fs = $preview ? 1 : 0.1;
$fa = $preview ? 5 : 1;

// Parameters for customization
mug_height = 130;          // Height of the mug
mug_diameter = 85;         // Outer diameter of the mug
wall_thickness = 4;        // Thickness of the mug wall
base_height = 15;          // Height of the base
rim_height = 15;           // Height of the rim at top
rim_thickness = 4;         // How much wider the rim is than the body
handle_thickness = 14;     // Thickness of the handle
handle_width = 40;         // Width of the handle (distance from mug)
handle_top_pos = 95;       // Position of top of handle from bottom
handle_bottom_pos = 35;    // Position of bottom of handle from bottom
ridges = 20;               // Number of ridges around the mug
ridge_height = 70;         // Height of the ridged section
ridge_depth = 1.5;         // Depth of the ridges
taper_ratio = 0.92;        // Taper ratio for the main body (bottom/top)
add_beer = true;           // Add beer and foam to the mug

module mug_body() {
    difference() {
        union() {
            // Base
            cylinder(h=base_height, r1=mug_diameter/2 * 1.1, r2=mug_diameter/2 * 1.05, center=false);
            
            // Main body with taper
            translate([0, 0, base_height])
            cylinder(h=mug_height-base_height-rim_height, 
                     r1=mug_diameter/2, 
                     r2=mug_diameter/2 * taper_ratio, center=false);
            
            // Rim
            translate([0, 0, mug_height-rim_height])
            cylinder(h=rim_height, 
                     r1=mug_diameter/2 * taper_ratio, 
                     r2=(mug_diameter/2 * taper_ratio) + rim_thickness, center=false);
            
            // Add decorative ridges
            translate([0, 0, base_height + 5])
            for(i = [0:ridges-1]) {
                rotate([0, 0, i * (360/ridges)])
                translate([mug_diameter/2 - ridge_depth/2, 0, 0])
                scale([1, 0.25, 1])
                cylinder(h=ridge_height, r=ridge_depth, center=false);
            }
            
            // Decorative band at base
            translate([0, 0, base_height - 5])
            difference() {
                cylinder(h=5, r=mug_diameter/2 * 1.05 + 1, center=false);
                translate([0, 0, -1])
                cylinder(h=7, r=mug_diameter/2 * 1.05 - 1, center=false);
            }
        }
        
        // Hollow out the inside - with taper
        translate([0, 0, base_height])
        cylinder(h=mug_height, 
                 r1=mug_diameter/2 - wall_thickness, 
                 r2=(mug_diameter/2 * taper_ratio) - wall_thickness, center=false);
    }
}

module handle() {
    // Create a handle with thicker attachments
    
    // Top attachment
    hull() {
        // Top attachment to mug
        translate([0, -mug_diameter/2 + wall_thickness/2, handle_top_pos])
        rotate([0, 90, 0])
        cylinder(h=wall_thickness * 2, r=handle_thickness/2 * 1.2, center=true);
        
        // Outer top curve
        translate([0, -mug_diameter/2 - handle_width + handle_thickness/2, handle_top_pos - handle_thickness/2])
        rotate([0, 90, 0])
        cylinder(h=wall_thickness * 1.5, r=handle_thickness/2, center=true);
    }
    
    // Middle section
    hull() {
        // Outer top curve
        translate([0, -mug_diameter/2 - handle_width + handle_thickness/2, handle_top_pos - handle_thickness/2])
        rotate([0, 90, 0])
        cylinder(h=wall_thickness * 1.5, r=handle_thickness/2, center=true);
        
        // Outer bottom curve
        translate([0, -mug_diameter/2 - handle_width + handle_thickness/2, handle_bottom_pos + handle_thickness/2])
        rotate([0, 90, 0])
        cylinder(h=wall_thickness * 1.5, r=handle_thickness/2, center=true);
    }
    
    // Bottom attachment
    hull() {
        // Outer bottom curve
        translate([0, -mug_diameter/2 - handle_width + handle_thickness/2, handle_bottom_pos + handle_thickness/2])
        rotate([0, 90, 0])
        cylinder(h=wall_thickness * 1.5, r=handle_thickness/2, center=true);
        
        // Bottom attachment to mug
        translate([0, -mug_diameter/2 + wall_thickness/2, handle_bottom_pos])
        rotate([0, 90, 0])
        cylinder(h=wall_thickness * 2, r=handle_thickness/2 * 1.2, center=true);
    }
}

module beer_and_foam() {
    beer_height = mug_height - base_height - wall_thickness - 25;
    foam_height = 20;
    
    // Beer liquid
    color([0.8, 0.4, 0.0, 0.8])  // Amber beer color
    translate([0, 0, base_height + wall_thickness])
    cylinder(h=beer_height, 
             r1=mug_diameter/2 - wall_thickness - 1, 
             r2=(mug_diameter/2 * taper_ratio) - wall_thickness - 1, center=false);
    
    // Beer foam
    color([1, 0.98, 0.94, 0.9])  // Off-white foam
    translate([0, 0, base_height + wall_thickness + beer_height])
    difference() {
        cylinder(h=foam_height, r=(mug_diameter/2 * taper_ratio) - wall_thickness - 1, center=false);
        
        // Add foam bubbles/irregularities
        for(i = [0:16]) {
            rotate([0, 0, i * 22.5])
            translate([(mug_diameter/4) * 0.8, 0, foam_height * 0.6])
            scale([1, 1, 0.7])
            sphere(r=foam_height/3);
        }
    }
}

// Complete mug with options
module beer_mug() {
    // Glass mug
    color([0.7, 0.8, 0.9, 0.6]) {  // Blue-tinted glass color
        mug_body();
        handle();
    }
    
    if (add_beer) {
        beer_and_foam();
    }
}

// Create the model
beer_mug();
生ビール生ビール

OpenCascade.js

https://github.com/donalffons/opencascade.js/

ここで試せる

https://zalo.github.io/CascadeStudio/

Claude 3.7-sonnet (think)

下記cascade studio viewerでのexampleを参考に、ビールジョッキのcascade studioのコードを作って。
---
// cascade studioのexample
---


コンテキスト雑だとあまり得意でないかも

Output
// Beer Mug in Cascade Studio
// Interactive parameters
let mugHeight = Slider("Mug Height", 120, 80, 160);
let mugRadius = Slider("Mug Radius", 40, 30, 60);
let wallThickness = Slider("Wall Thickness", 5, 2, 10);
let handleThickness = Slider("Handle Thickness", 8, 4, 15);

// Create the outer body of the mug
let outerBody = Cylinder(mugRadius, mugHeight, true);

// Create the inner cavity by subtracting a smaller cylinder
let innerBody = Translate([0, 0, wallThickness], 
                        Cylinder(mugRadius - wallThickness, mugHeight, true));

// Create the main body with hollow interior
let mugBody = Difference(outerBody, innerBody);

// Create handle with three cylinders in a C shape
// Distance from mug to handle
let handleDistance = 15;

// Top horizontal part of handle
let handleTop = Translate([0, mugRadius + handleDistance/2, mugHeight * 0.7], 
                        Rotate([1, 0, 0], 90, 
                                Cylinder(handleThickness/2, handleDistance, true)));

// Bottom horizontal part of handle
let handleBottom = Translate([0, mugRadius + handleDistance/2, mugHeight * 0.3], 
                            Rotate([1, 0, 0], 90, 
                                Cylinder(handleThickness/2, handleDistance, true)));

// Vertical part of handle connecting top and bottom
let handleSide = Translate([0, mugRadius + handleDistance, mugHeight * 0.5],
                        Cylinder(handleThickness/2, mugHeight * 0.4, true));

// Combine all handle parts
let handle = Union([handleTop, handleBottom, handleSide]);

// Combine the mug body and handle
let mug = Union(mugBody, handle);

// Add a beer label
let addLabel = Checkbox("Add Label", true);
if (addLabel) {
    let beerText = Text3D("BEER", 20, 0.15, 'Arial');
    beerText = Translate([-15, -mugRadius+1, mugHeight/2], 
                        Rotate([0, 0, 1], 180, Rotate([1, 0, 0], 90, beerText)));
    mug = Union(mug, beerText);
}

// Optional: Add some froth
let addFroth = Checkbox("Add Froth", true);
if (addFroth) {
    let frothHeight = 10;
    let froth = Translate([0, 0, mugHeight - frothHeight], 
                        Cylinder(mugRadius - wallThickness, frothHeight, true));
    mug = Union(mug, froth);
}

// Display the final mug
mug;
生ビール生ビール

Replicad

https://github.com/sgenoud/replicad

ここで試せる

https://studio.replicad.xyz/workbench

Claude 3.7-sonnet (think)

下記replicad viewerでのexampleを参考に、ビールジョッキのreplicadのコードを作って。
---
// replicadのexample


エラーを貼り付けて3ターンで完成

Output
const { makePlane, makeCylinder, draw, drawCircle } = replicad;

const defaultParams = {};

const main = () => {
  // Define dimensions for a simple beer mug
  const baseRadius = 30;      // Radius at the base
  const topRadius = 32;       // Radius at the top
  const height = 100;         // Total height of the mug
  const thickness = 3;        // Wall thickness
  
  // Building a simple beer mug profile
  const profile = draw()
    .hLine(baseRadius)                          // Bottom radius
    .line(topRadius - baseRadius, height * 0.8) // Slightly widen as we go up
    .vLine(height * 0.2)                        // Straight wall at the top
    .hLine(-thickness)                          // Top rim thickness
    .vLine(-(height * 0.2))                     // Inner wall top section
    .line(-(topRadius - thickness - baseRadius + thickness), -(height * 0.8)) // Inner wall tapered section
    .hLine(-(baseRadius - thickness))           // Bottom inner wall
    .close();                                   // Close the profile

  // Revolve the profile around the Z-axis to create the mug body
  const mugBody = profile.sketchOnPlane("XZ").revolve([0, 0, 1]);
  
  // Create a simple handle
  // Create two circles that we'll loft to make a handle
  const topHandlePlane = makePlane().translate([baseRadius, 0, height * 0.75]);
  const topHandle = drawCircle(4).sketchOnPlane(topHandlePlane);
  
  const middleHandlePlane = makePlane().translate([baseRadius + 20, 0, height * 0.5]);
  const middleHandle = drawCircle(4).sketchOnPlane(middleHandlePlane);
  
  const bottomHandlePlane = makePlane().translate([baseRadius, 0, height * 0.25]);
  const bottomHandle = drawCircle(4).sketchOnPlane(bottomHandlePlane);
  
  // Loft the circles to create the handle
  const handle = topHandle.loftWith([middleHandle, bottomHandle]);
  
  // Combine the mug body and handle
  const beerMug = mugBody.fuse(handle);
  
  return {
    shape: beerMug,
    name: "Simple Beer Mug",
  };
};
生ビール生ビール

OpenJSCAD

https://github.com/jscad/OpenJSCAD.org

ここで試せる

https://openjscad.xyz/#

Claude 3.7-sonnet (think)

下記openjscad viewerでのexampleを参考に、ビールジョッキのopenjscadのコードを作って。
---
// OpenJSCADのexample


エラー貼り付けて4ターンで完成

Output
/**
 * Basic Beer Mug in OpenJSCAD
 * @category Creating Shapes
 * @description A very basic beer mug closely following the example structure
 * @tags mug, beer
 * @licence MIT License
 */

const jscad = require('@jscad/modeling')
const { cylinder } = jscad.primitives
const { subtract, union } = jscad.booleans
const { colorize } = jscad.colors
const { translate } = jscad.transforms

const options = {
  mugHeight: 100,         // Height of the mug in mm
  mugRadius: 40,          // Radius of the mug in mm
  wallThickness: 4,       // Wall thickness in mm
  handleThickness: 8,     // Thickness of the handle in mm
  segments: 32            // Number of segments for circular shapes
}

const main = () => {
  return [
    colorize([0.95, 0.9, 0.8], beerMug(options))
  ]
}

// Create the beer mug
const beerMug = (options) => {
  // Create outer cylinder
  const outer = cylinder({
    height: options.mugHeight,
    radius: options.mugRadius,
    segments: options.segments,
    center: [0, 0, options.mugHeight/2]
  })
  
  // Create inner cylinder (hollow part)
  const inner = cylinder({
    height: options.mugHeight - options.wallThickness,
    radius: options.mugRadius - options.wallThickness,
    segments: options.segments,
    center: [0, 0, options.mugHeight/2 + options.wallThickness/2]
  })
  
  // Basic mug body
  const body = subtract(outer, inner)
  
  // Create handle using cylinder primitives
  const handle = createSimpleHandle(options)
  
  return union(body, handle)
}

// Create a simple handle made of cylinders
const createSimpleHandle = (options) => {
  const { mugRadius, mugHeight, handleThickness } = options
  
  // Vertical cylinder for the handle
  const verticalPart = cylinder({
    height: mugHeight * 0.6,
    radius: handleThickness / 2,
    segments: options.segments,
    center: [mugRadius + handleThickness/2, 0, mugHeight * 0.5]
  })
  
  // Top horizontal cylinder
  const topPart = cylinder({
    height: handleThickness,
    radius: handleThickness / 2,
    segments: options.segments,
    center: [mugRadius - handleThickness/2, 0, mugHeight * 0.7]
  })
  
  // Bottom horizontal cylinder
  const bottomPart = cylinder({
    height: handleThickness,
    radius: handleThickness / 2,
    segments: options.segments,
    center: [mugRadius - handleThickness/2, 0, mugHeight * 0.3]
  })
  
  // Rotate horizontal cylinders to connect to vertical part
  const rotatedTop = translate([handleThickness, 0, 0], 
    cylinder({
      height: handleThickness * 2,
      radius: handleThickness / 2,
      segments: options.segments,
      center: [mugRadius, 0, mugHeight * 0.7]
    })
  )
  
  const rotatedBottom = translate([handleThickness, 0, 0], 
    cylinder({
      height: handleThickness * 2,
      radius: handleThickness / 2,
      segments: options.segments,
      center: [mugRadius, 0, mugHeight * 0.3]
    })
  )
  
  // Combine all parts
  return union(
    verticalPart,
    topPart,
    bottomPart,
    rotatedTop,
    rotatedBottom
  )
}

module.exports = { main }
生ビール生ビール

各ツールの系統

※o1 Pro & Claude3.7-sonnetに整理してもらったもののマージ

Open CASCADE (OCCT, C++ライブラリ)
    │
    ├─ OpenCascade.js (OCCT をブラウザ向けに WASM 化したもの)
    │      ├─ CascadeStudio(Web アプリとして動作する簡易な CAD 環境)
    │      └─ replicad(OpenCascade.js を使った JS/TS ライブラリ)
    │
    ├─ CadQuery(Python から OCCT を扱いやすくしたライブラリ)
    │      └─ build123d(CadQuery の開発者コミュニティによる別プロジェクト)
    │
    └─ (他にも pythonOCC / OCP ベースのプロジェクトが存在)
       
OpenSCAD(OCCT とは独立した独自言語ベースのスクリプトCAD)
    └─ OpenJSCAD(JavaScript ベースの同様のアプローチ)