外科用固定プレート
このノートブックでは,OpenCascadeLinkを使って,パラメータ設計に基づいた外科用固定プレートを作成する方法について説明する.
外科用固定プレートとは,折れた骨が治癒する過程において固定しサポートするために使われる医療器具である.チタンの固定プレートでも特に前腕用に設計されたものは,その強度,生体適合性,耐腐食性のために好まれる.これらのプレートは,骨折骨にネジで外科的に取り付けられ,骨が正しく一直線になるようにし,そして効果的な回復を促進する.パラメータ設計を使うことによって,患者のニーズに基づいて最適な治療を行い,器具を容易にカスタマイズすることができる.
固定プレートの設計は,固定プレートの長さと幅についてのパラメトリック形状関数につながる分析的記述に基づく.OpenCascadeを使った作成手順は,平面の記述から始め,それを後から押し出して3Dオブジェクトを形成する.
Needs["OpenCascadeLink`"]
Needs["NDSolve`FEM`"]形状
固定プレートは,中央部分と両側の2つの固定部分に分けられる.固定部分と中央部分はそれぞれ3つの穴がある.
サイズを希望する長さと幅の関数として表現した外科用固定プレートの平面の二次元工業的ダイアグラム.固定プレートは,それぞれの長さが長さ/3である3つの部分に分けられる.
3D形状を作成するために,2D設計図が作られ,それを押し出して3Dにする.この2D設計図を作るために,辺はすべてパラメータ化され,つなげられて,平面の2D面を形成する.その面から穴の部分を削除し,最後に穴を開けられた面を押し出して3Dにする.
最初のステップは2Dプレートの上の辺を作成することである.この長い辺は,それぞれの領域に希望数の穴をフィットするようにスケールされた正弦関数で表される3つの領域に分割することができる.形状特性はセンチメートルで表される.
length = 16;
thickness = 0.3;
width = 1;
waveAmplitude = 0.15;numberFixationHoles = 3;
radiusFixationHoles = 0.3;正弦関数を使って,周期のそれぞれの正の波動サイクル内に固定プレートの穴を配置する.周期は固定の穴の数の2倍で使用可能な長さを割って求める.
ϕ = (length/3)(1/numberFixationHoles * 2)fixationEdge[x_] := Sin[(π x/ϕ)]centralEdge[x_] := fixationEdge[(x/6)]edge[x_] := (width/2) + waveAmplitude * Which[
x <= (length/3), fixationEdge[x],
(length/3) < x <= (length/2), -centralEdge[x]]edgePlot = Plot[edge[x + length / 2], {x, -length / 2, 0}, AspectRatio -> Automatic, ImageSize -> Large, Ticks -> {True, False}]次のステップは,この辺のプロットをスプラインに変換することである.そのために辺が離散化,ダウンサンプリングされ,BSplineCurveに変換される.
discretedEdge = DiscretizeGraphics[edgePlot]topEdgeCoords = MeshCoordinates[discretedEdge][[1 ;; -1 ;; 15]];topEdgeCoords[[-1, 1]] = 0.;Show[discretedEdge, Graphics[{Red, Point[topEdgeCoords]}]]topEdgeSpline = BSplineCurve[topEdgeCoords];
Graphics[topEdgeSpline]次のステップは,形状の左の辺を作ることであり,これは円状のセクターで表すことができる.難しいのはセクターの厳密なサイズを求めることである.この過程を容易にするため,半円と上の辺,そして半円と交差する上の辺の延長線を可視化すると便利である.
leftCircleCenter = {-length / 2 + width / 2, 0}circleSegement = Circle[leftCircleCenter, width, {π / 2, π}]extensionLine = Line[{topEdgeCoords[[1]], {leftCircleCenter[[1]] - width, topEdgeCoords[[1, 2]]}}]Graphics[{topEdgeSpline, {Red, extensionLine}, circleSegement}]延長線と半円の交差点が計算されると,左の辺のセクターを決定することができる.
intersectionPoint = RegionIntersection[extensionLine, circleSegement]leftIntersectionCoord = intersectionPoint[[1, 1]]leftIntersectAngle = NSolveValues[leftIntersectionCoord[[1]] == leftCircleCenter[[1]] + width * Cos[θ], θ, MaxRoots -> 1][[1]]leftLine = Line[{leftIntersectionCoord, topEdgeCoords[[1]]}];
leftEdge = Circle[leftCircleCenter, width, {2π - leftIntersectAngle, π}];
Graphics[{topEdgeSpline, {Red, leftLine}, leftEdge}]rt1 = ReflectionTransform[{1, 0}, {0, 0}];tr1 = TransformedRegion[topEdgeSpline, rt1];
tr2 = TransformedRegion[leftLine, rt1];
tr3 = TransformedRegion[leftEdge, rt1];
tr3 = tr3 /. Circle[c_List, r_, s_] :> Circle[c, r, {0, s[[1]]}];
Graphics[{topEdgeSpline, leftLine, leftEdge, {Blue, tr1}, {Red, tr2}, {Magenta, tr3}}]e1 = OpenCascadeShape[leftEdge];
e2 = OpenCascadeShape[leftLine];
e3 = OpenCascadeShape[topEdgeSpline];
e4 = OpenCascadeShape[tr1];
e5 = OpenCascadeShape[tr2];
e6 = OpenCascadeShape[tr3];w1 = OpenCascadeShapeWire[{e1, e2, e3, e4, e5, e6}]rt2 = ReflectionTransform[{0, -1}, {0, 0}];gt1 = GeometricTransformation[topEdgeSpline, rt2];
gt2 = GeometricTransformation[leftLine, rt2];
gt3 = GeometricTransformation[leftEdge, rt2];
Graphics[{topEdgeSpline, leftLine, leftEdge, {Blue, gt1}, {Red, gt2}, {Magenta, gt3}}]w2 = OpenCascadeShapeTransformation[w1, rt2]face = OpenCascadeShapeFace[{w1, w2}]bmesh = OpenCascadeShapeSurfaceMeshToBoundaryMesh[face];
bmesh["Wireframe"]次のステップは,固定プレートに穴を開けることである.3つのグループの穴がある.2つのグループの固定部分の穴と中央の穴である.固定部分の穴は,正弦の空間的周期
, と一直線に並ぶ円で表され,中央の穴は,下に説明される超楕円境界で表される.
holesCentersAlongX = Table[-length / 2 + (2i - 3 / 2)ϕ, {i, 1, 3, 1}];holesCentersAlongX = Join[holesCentersAlongX, -#& /@ holesCentersAlongX];sideHoles = OpenCascadeShape[Disk[{#, 0}, radiusFixationHoles]]& /@ holesCentersAlongX;超楕円は方程式
で表される.ここで
と
は半軸長を表す.さらに穴は45°回転させる.
a = 0.2;
b = 0.5;
n = 3;hyperellipseFun[a_, b_, n_] := Abs[(x/a)]^n + Abs[(y/b)]^n == 1discretizedHyperellipse = DiscretizeRegion[Rotate[Scale[Region@ImplicitRegion[hyperellipseFun[a, b, n], {x, y}], (width/1.25){1, 1}], -π / 4]];hyperellipsePts = MeshCoordinates[discretizedHyperellipse];centralHoleFun[l_] := {#[[1]] + l, #[[2]]}& /@ hyperellipsePts;centralHoles = OpenCascadeShape[Polygon[centralHoleFun[#]]]& /@ Table[((length/10))i, {i, -1, 1, 1}];holes = OpenCascadeShapeUnion[Join[sideHoles, centralHoles]];base = OpenCascadeShapeDifference[face, holes]OpenCascadeShapeSurfaceMeshToBoundaryMesh[base]["Wireframe"["MeshElementStyle" -> Directive[FaceForm[LightBlue], EdgeForm[]]]]メッシュ
最後に線形スイープを使って,平面を3Dオブジェクトに変換することができる.その後OpenCascade形状は,適切な大きさの希望の形状を表す境界メッシュと中空ではないメッシュに変換することができる.
shape3D = OpenCascadeShapeLinearSweep[base, {{0, 0, 0}, {0, 0, thickness}}];(bmesh = OpenCascadeShapeSurfaceMeshToBoundaryMesh[shape3D])["Wireframe"](mesh = ToElementMesh[bmesh])["Wireframe"]SetLengthUnit[mesh, "Centimeters"]plateMeshed = ElementMeshCoordinateRescale[mesh, "Meters"];plateMeshed["Wireframe"["MeshElementStyle" -> Directive[EdgeForm[], FaceForm[Gray]]]]