# 欧霓博 SC 系列示例数据生成器：STEP 变体文件 + params.csv
# 用法: powershell -NoProfile -ExecutionPolicy Bypass -File tools\gen-step.ps1
# 说明: 以极简封闭 B-rep 圆柱（MANIFOLD_SOLID_BREP）组合出简化气缸模型
#       (后盖 + 缸体 + 前盖 + 活塞杆 4 个实体), 尺寸随缸径/行程参数变化。

param(
  [string]$OutDir = (Join-Path $PSScriptRoot '..\onb-sc')
)

$inv = [System.Globalization.CultureInfo]::InvariantCulture
$stepDir = Join-Path $OutDir 'step'
$csvPath = Join-Path $OutDir 'params.csv'
New-Item -ItemType Directory -Force -Path $stepDir | Out-Null

function Format-Num([double]$v) { return $v.ToString('0.###', $inv) }

# 单个圆柱实体的实体行 (OCCT 兼容拓扑: 顶点在圆周上+全圆闭边+接缝边, 共 36 个实体)
# 约定: 圆心点 = (x, 0, z) 是仅有的 y=0 点 (供解析器识别); 顶点 = (x, r, z) 在 +Y 方向
function New-CylinderEntities([int]$id, [double]$x, [double]$y, [double]$z, [double]$r, [double]$len) {
  $X  = Format-Num $x
  $Y  = Format-Num $y
  $Z  = Format-Num $z
  $ZT = Format-Num ($z + $len)
  $R  = Format-Num $r
  $VY = Format-Num ($y + $r)      # 顶点在圆周 +Y 处 (y=0 留给圆心供解析)
  $e = @(
    "#$($id)=DIRECTION('',(0.,0.,1.));",                                     # 轴
    "#$($id+1)=CARTESIAN_POINT('',($X,$Y,$Z));",                             # 底圆心
    "#$($id+2)=CARTESIAN_POINT('',($X,$Y,$ZT));",                            # 顶圆心
    "#$($id+3)=DIRECTION('',(1.,0.,0.));",                                   # 参考方向
    "#$($id+4)=AXIS2_PLACEMENT_3D('',#$($id+1),#$($id),#$($id+3));",         # 底放置
    "#$($id+5)=CARTESIAN_POINT('',($X,$VY,$Z));",                            # 底顶点(圆周上)
    "#$($id+6)=CARTESIAN_POINT('',($X,$VY,$ZT));",                           # 顶顶点(圆周上)
    "#$($id+7)=VERTEX_POINT('',#$($id+5));",
    "#$($id+8)=VERTEX_POINT('',#$($id+6));",
    "#$($id+9)=CIRCLE('',#$($id+4),$R);",                                    # 底圆
    "#$($id+10)=EDGE_CURVE('',#$($id+7),#$($id+7),#$($id+9),.T.);",          # 底圆闭边
    "#$($id+11)=CYLINDRICAL_SURFACE('',#$($id+4),$R);",
    "#$($id+12)=PLANE('',#$($id+4));",                                       # 底面
    "#$($id+13)=DIRECTION('',(0.,0.,1.));",
    "#$($id+14)=AXIS2_PLACEMENT_3D('',#$($id+2),#$($id+13),#$($id+3));",     # 顶放置
    "#$($id+15)=PLANE('',#$($id+14));",                                      # 顶面
    "#$($id+16)=CIRCLE('',#$($id+14),$R);",                                  # 顶圆
    "#$($id+17)=EDGE_CURVE('',#$($id+8),#$($id+8),#$($id+16),.T.);",         # 顶圆闭边
    "#$($id+18)=DIRECTION('',(0.,0.,1.));",
    "#$($id+19)=VECTOR('',#$($id+18),1.);",
    "#$($id+20)=LINE('',#$($id+5),#$($id+19));",                             # 接缝线
    "#$($id+21)=EDGE_CURVE('',#$($id+7),#$($id+8),#$($id+20),.T.);",         # 接缝边
    "#$($id+22)=ORIENTED_EDGE('',*,*,#$($id+10),.T.);",                      # 底环
    "#$($id+23)=ORIENTED_EDGE('',*,*,#$($id+17),.T.);",                      # 顶环
    "#$($id+24)=ORIENTED_EDGE('',*,*,#$($id+21),.T.);",                      # 壁环: 缝上
    "#$($id+25)=ORIENTED_EDGE('',*,*,#$($id+17),.T.);",
    "#$($id+26)=ORIENTED_EDGE('',*,*,#$($id+21),.F.);",                      # 缝下
    "#$($id+27)=ORIENTED_EDGE('',*,*,#$($id+10),.F.);",
    "#$($id+28)=EDGE_LOOP('',(#$($id+22)));",
    "#$($id+29)=EDGE_LOOP('',(#$($id+23)));",
    "#$($id+30)=EDGE_LOOP('',(#$($id+24),#$($id+25),#$($id+26),#$($id+27)));",
    "#$($id+31)=ADVANCED_FACE('',(#$($id+30)),#$($id+11),.T.);",             # 柱壁
    "#$($id+32)=ADVANCED_FACE('',(#$($id+28)),#$($id+12),.F.);",             # 底面(法线朝下)
    "#$($id+33)=ADVANCED_FACE('',(#$($id+29)),#$($id+15),.T.);",             # 顶面(法线朝上)
    "#$($id+34)=CLOSED_SHELL('',(#$($id+31),#$($id+32),#$($id+33)));",
    "#$($id+35)=MANIFOLD_SOLID_BREP('',#$($id+34));"
  )
  return $e
}

# 尾部共享实体: 每个实体注入 STYLED_ITEM 颜色 (occt-import-js 对无颜色模型会崩)
# 从 $id 开始: 每实体 7 个颜色实体 + 14 个尾部实体
function New-TailEntities([int]$id, [int[]]$solidIds) {
  $t = New-Object System.Collections.Generic.List[string]
  $styled = New-Object System.Collections.Generic.List[string]
  $c = $id
  foreach ($s in $solidIds) {
    $t.Add("#$c=COLOUR_RGB('',0.65,0.72,0.85);")
    $t.Add("#$($c+1)=FILL_AREA_STYLE_COLOUR('',#$c);")
    $t.Add("#$($c+2)=SURFACE_STYLE_FILL_AREA(#$($c+1));")
    $t.Add("#$($c+3)=SURFACE_SIDE_STYLE('',(#$($c+2)));")
    $t.Add("#$($c+4)=SURFACE_STYLE_USAGE(.BOTH.,#$($c+3));")
    $t.Add("#$($c+5)=PRESENTATION_STYLE_ASSIGNMENT((#$($c+4)));")
    $t.Add("#$($c+6)=STYLED_ITEM('',(#$($c+5)),#$s);")
    $styled.Add("#$($c+6)")
    $c += 7
  }
  $items = (($solidIds | ForEach-Object { "#$_" }) + $styled) -join ','
  $t.Add("#$c=SHAPE_REPRESENTATION('',($items),#$($c+1));")
  $t.Add("#$($c+1)=(GEOMETRIC_REPRESENTATION_CONTEXT(3)GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#$($c+2)))GLOBAL_UNIT_ASSIGNED_CONTEXT((#$($c+3),#$($c+4),#$($c+5)))REPRESENTATION_CONTEXT('',''));")
  $t.Add("#$($c+2)=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-06),#$($c+3),'');")
  $t.Add("#$($c+3)=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));")
  $t.Add("#$($c+4)=(NAMED_UNIT(*)PLANE_ANGLE_UNIT()SI_UNIT($,.RADIAN.));")
  $t.Add("#$($c+5)=(NAMED_UNIT(*)SI_UNIT($,.STERADIAN.)SOLID_ANGLE_UNIT());")
  $t.Add("#$($c+6)=PRODUCT('OUNIBO_SC','OUNIBO_SC','',(#$($c+7)));")
  $t.Add("#$($c+7)=PRODUCT_CONTEXT('',#$($c+8),'mechanical');")
  $t.Add("#$($c+8)=APPLICATION_CONTEXT('configuration controlled 3d designs of mechanical parts and assemblies');")
  $t.Add("#$($c+9)=PRODUCT_DEFINITION_FORMATION('','',#$($c+6));")
  $t.Add("#$($c+10)=PRODUCT_DEFINITION('design','',#$($c+9),#$($c+11));")
  $t.Add("#$($c+11)=PRODUCT_DEFINITION_CONTEXT('part definition',#$($c+8),'design');")
  $t.Add("#$($c+12)=PRODUCT_DEFINITION_SHAPE('','',#$($c+10));")
  $t.Add("#$($c+13)=SHAPE_DEFINITION_REPRESENTATION(#$($c+12),#$c);")
  return $t
}

# ---- 型号与规则定义 (见 coding-rules.md) ----
# 缸径 16: 行程仅 25/50, 无磁石; 磁石 S 要求缸径>=25; 中摆 CB 要求行程<=75
$bores = @(16, 25, 32, 40)
$strokesAll = @(25, 50, 75, 100)
$mountsAll  = @('FA', 'LB', 'CB')

$encNoBom = New-Object System.Text.UTF8Encoding($false)
$encBom   = New-Object System.Text.UTF8Encoding($true)
$csvLines = New-Object System.Collections.Generic.List[string]
$csvLines.Add('model_code,bore,stroke,magnet,mount,step_file')

$count = 0
foreach ($bore in $bores) {
  $strokes = if ($bore -eq 16) { @(25, 50) } else { $strokesAll }
  $magnets = if ($bore -eq 16) { @('') } else { @('', 'S') }
  foreach ($stroke in $strokes) {
    $mounts = if ($stroke -gt 75) { @('FA', 'LB') } else { $mountsAll }
    foreach ($magnet in $magnets) {
      foreach ($mount in $mounts) {
        $model = "SC$bore`x$stroke$magnet-$mount"
        $stepFile = "$model.step"

        # ---- 简化气缸尺寸 (mm): 后盖 + 缸体 + 前盖 + 活塞杆, 沿 Z 轴 ----
        $bodyR   = $bore / 2.0 + 2.0        # 缸体外径
        $bodyLen = $stroke + 60.0           # 缸体长度(随行程)
        $capR    = $bore / 2.0 + 5.0        # 端盖外径
        $capLen  = 8.0                      # 后盖厚度
        $fcapLen = 10.0                     # 前盖厚度
        $rodR    = [Math]::Max($bore / 5.0, 3.0)
        $rodBot  = $bodyLen - 14.0          # 活塞杆埋入缸体
        $rodLen  = $stroke + 34.0

        $lines = New-Object System.Collections.Generic.List[string]
        $lines.Add('ISO-10303-21;')
        $lines.Add('HEADER;')
        $lines.Add("FILE_DESCRIPTION(('OUNIBO SC series sample part $model'),'2;1');")
        $lines.Add("FILE_NAME('$stepFile','2026-06-02T00:00:00',('OUNIBO'),('OUNIBO'),'','','');")
        $lines.Add("FILE_SCHEMA(('CONFIG_CONTROL_DESIGN'));")
        $lines.Add('ENDSEC;')
        $lines.Add('DATA;')

        $ids = New-Object System.Collections.Generic.List[int]
        $nextId = 1
        $cyls = New-Object System.Collections.Generic.List[object]
        $cyls.Add(@{ z = -$capLen; r = $capR;   len = $capLen  })   # 后盖
        $cyls.Add(@{ z = 0.0;      r = $bodyR;  len = $bodyLen })   # 缸体
        $cyls.Add(@{ z = $bodyLen; r = $capR;   len = $fcapLen })   # 前盖
        $cyls.Add(@{ z = $rodBot;  r = $rodR;   len = $rodLen  })   # 活塞杆
        foreach ($cyl in $cyls) {
          [string[]]$entities = New-CylinderEntities -id $nextId -x 0 -y 0 -z $cyl['z'] -r $cyl['r'] -len $cyl['len']
          $lines.AddRange($entities)
          $ids.Add($nextId + 35)                                # MANIFOLD_SOLID_BREP 实体号
          $nextId += 36
        }
        [string[]]$tail = New-TailEntities -id $nextId -solidIds $ids.ToArray()
        $lines.AddRange($tail)
        $lines.Add('ENDSEC;')
        $lines.Add('END-ISO-10303-21;')

        [System.IO.File]::WriteAllLines((Join-Path $stepDir $stepFile), $lines.ToArray(), $encNoBom)
        $csvLines.Add("$model,$bore,$stroke,$magnet,$mount,$stepFile")
        $count++
      }
    }
  }
}

# ---- MAQ 迷你气缸系列 (多系列演示): 缸径 6/10/16, 行程 10/20/30/40 ----
# 规则: 缸径 6 仅行程 10/20 且无磁石; 安装仅 FA/LB
$csvLinesM = New-Object System.Collections.Generic.List[string]
$csvLinesM.Add('model_code,bore,stroke,magnet,mount,step_file')
$countM = 0
foreach ($bore in @(6, 10, 16)) {
  $strokes = if ($bore -eq 6) { @(10, 20) } else { @(10, 20, 30, 40) }
  $magnets = if ($bore -eq 6) { @('') } else { @('', 'S') }
  foreach ($stroke in $strokes) {
    foreach ($magnet in $magnets) {
      foreach ($mount in @('FA', 'LB')) {
        $model = "MAQ$bore`x$stroke$magnet-$mount"
        $stepFile = "$model.step"

        $bodyR   = $bore / 2.0 + 1.5
        $bodyLen = $stroke + 40.0
        $capR    = $bore / 2.0 + 4.0
        $capLen  = 6.0
        $fcapLen = 8.0
        $rodR    = [Math]::Max($bore / 5.0, 2.0)
        $rodBot  = $bodyLen - 10.0
        $rodLen  = $stroke + 24.0

        $lines = New-Object System.Collections.Generic.List[string]
        $lines.Add('ISO-10303-21;')
        $lines.Add('HEADER;')
        $lines.Add("FILE_DESCRIPTION(('OUNIBO MAQ series sample part $model'),'2;1');")
        $lines.Add("FILE_NAME('$stepFile','2026-06-02T00:00:00',('OUNIBO'),('OUNIBO'),'','','');")
        $lines.Add("FILE_SCHEMA(('CONFIG_CONTROL_DESIGN'));")
        $lines.Add('ENDSEC;')
        $lines.Add('DATA;')

        $ids = New-Object System.Collections.Generic.List[int]
        $nextId = 1
        $cyls = New-Object System.Collections.Generic.List[object]
        $cyls.Add(@{ z = -$capLen; r = $capR;   len = $capLen  })
        $cyls.Add(@{ z = 0.0;      r = $bodyR;  len = $bodyLen })
        $cyls.Add(@{ z = $bodyLen; r = $capR;   len = $fcapLen })
        $cyls.Add(@{ z = $rodBot;  r = $rodR;   len = $rodLen  })
        foreach ($cyl in $cyls) {
          [string[]]$entities = New-CylinderEntities -id $nextId -x 0 -y 0 -z $cyl['z'] -r $cyl['r'] -len $cyl['len']
          $lines.AddRange($entities)
          $ids.Add($nextId + 35)
          $nextId += 36
        }
        [string[]]$tail = New-TailEntities -id $nextId -solidIds $ids.ToArray()
        $lines.AddRange($tail)
        $lines.Add('ENDSEC;')
        $lines.Add('END-ISO-10303-21;')

        [System.IO.File]::WriteAllLines((Join-Path $stepDir $stepFile), $lines.ToArray(), $encNoBom)
        $csvLinesM.Add("$model,$bore,$stroke,$magnet,$mount,$stepFile")
        $countM++
      }
    }
  }
}

[System.IO.File]::WriteAllLines($csvPath, $csvLines.ToArray(), $encBom)
[System.IO.File]::WriteAllLines((Join-Path $OutDir 'params_maq.csv'), $csvLinesM.ToArray(), $encBom)
Write-Output "生成完成: SC $count 个 + MAQ $countM 个 STEP 文件 -> $stepDir"
Write-Output "参数表: $csvPath / params_maq.csv"
