こちらの続きを考えてます。
速度を落とさず、Undo歴をスッキリ3 - C#ATIA
思ったより高速になったので、もうちょっと頑張っちゃいたい気持ちもあるので
テストしました。
あちらは円フィッティングした円しか作れないのですが、人によっては
外接円や内接円も欲しい様な気がしてます。
(僕が検査している時は、そんな時ありました)
そこで安易なアルゴリズムで挑戦しました。
外接円 -> フィッテイング円の中心を利用して、ポリゴン頂点の一番遠い位置を半径として円を作成
内接円 -> フィッテイング円の中心を利用して、ポリゴンの辺の一番近い位置を半径として円を作成
こんな感じです。
※numpy使ってます。試したい場合はそれなりに書き換えてください。
# Fusion360API Python script import traceback import adsk.fusion import adsk.core import inspect import os import sys script_path = os.path.abspath(inspect.getfile(inspect.currentframe())) script_dir = os.path.dirname(script_path) if os.name == "posix": sys.path.append(script_dir + "/ModulesMac") else: sys.path.append(script_dir + "/ModulesWin") try: import numpy as np finally: del sys.path[-1] def run(context): ui = adsk.core.UserInterface.cast(None) try: app: adsk.core.Application = adsk.core.Application.get() ui = app.userInterface des: adsk.fusion.Design = app.activeProduct root: adsk.fusion.Component = des.rootComponent skt: adsk.fusion.Sketch = root.sketches[0] lines = skt.sketchCurves.sketchLines # フィッティング円 fitCir = _getFittingCircle(lines) drawCircle(fitCir, skt) # フィッティング円の中心を利用して最大の外接円 maxCir = getMaxCircle(fitCir, lines) drawCircle(maxCir, skt) # フィッティング円を中心を利用して線との最短距離を # 半径とする内接円 innerCir = getInnerCircle(fitCir, lines) drawCircle(innerCir, skt) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) def getInnerCircle( circle: adsk.core.Circle3D, lines: list) -> adsk.core.Circle3D: app: adsk.core.Application = adsk.core.Application.get() mars: adsk.core.MeasureManager = app.measureManager center: adsk.core.Point3D = circle.center def getMinimumDist_Center(line: adsk.fusion.SketchLine) ->float: res: adsk.core.MeasureResults = mars.measureMinimumDistance(center, line) return res.value line: adsk.fusion.SketchLine minRadius = min([getMinimumDist_Center(line) for line in lines]) clone: adsk.core.Circle3D = circle.copy() clone.radius = minRadius return clone def getMaxCircle( circle: adsk.core.Circle3D, lines: list) -> adsk.core.Circle3D: center: adsk.core.Point3D = circle.center line: adsk.fusion.SketchLine pnts = [line.startSketchPoint.geometry for line in lines] maxRadius = max([center.distanceTo(p) for p in pnts]) clone: adsk.core.Circle3D = circle.copy() clone.radius = maxRadius return clone def drawCircle( circle: adsk.core.Circle3D, skt: adsk.fusion.Sketch): circles: adsk.fusion.SketchCircles = skt.sketchCurves.sketchCircles circles.addByCenterRadius(circle.center, circle.radius) def _getFittingCircle( lines: list) -> adsk.core.Circle3D: # https://mori-memo.hateblo.jp/entry/2020/04/27/205437 points = [l.startSketchPoint.geometry for l in lines] x = np.array([p.x for p in points]) y = np.array([p.y for p in points]) A = np.vstack((x, y, np.ones((len(x))))).T v = -(x ** 2 + y ** 2) u, residuals, rank, s = np.linalg.lstsq(A, v, rcond=None) cx_pred = u[0] / (-2) cy_pred = u[1] / (-2) r_pred = np.sqrt(cx_pred ** 2 + cy_pred ** 2 - u[2]) return adsk.core.Circle3D.createByCenter( adsk.core.Point3D.create(cx_pred, cy_pred, 0), adsk.core.Vector3D.create(0, 0, 1), r_pred )
スケッチにポリゴンコマンドで描き、破壊し一か所をちょっと移動。
その状態でスクリプトを実行した結果はこれ。
赤:フィッティング円
青:外接円っぽい奴
緑:内接円っぽい奴
それなりに出来ているような気がしないでもないです。
もうちょっと歪な形状で試すと・・・
外接円もかなり怪しいし、内接円に至っては内接すらしていないと言う悲劇。
フィッティング円の中心は使えないんですね。(中学生の数学レベルのお話かな?)
三角形の外接円や内接円の中心求め方は、検索すれば幾らでもHitするんだけど、
どうなんだろう? ポリゴンを三角形に分割するのかな?