2010-11-26 1 views
2

任意の形状のGraphicsPathを定義されたスペース(ほとんどの場合、長方形または円)に「フィット」させる必要があります。C#のGraphicsPathポリゴンフィッティング

現在、Matrixオブジェクトを使用してGraphicsPathを拡大/縮小してもスケーリングはうまく動作しますが、スケールファクタが問題になります。

私が思い付くことができる最高の技術では、地域にGraphicsPathに変換地域に四角形や円を変換し、実行している:

rgnShape.Intersect(rgnCircle); 

してからかどうかのチェック:

rgnShape.IsEmpty() 

しかし、これは、形状が大きすぎてフィットすることができないということを伝え、形状をより小さなものにし、再度試してみる必要があります。

ポリゴンGraphicsPathに合わせてスケーリング係数を簡単に計算して、円に完全に収まるようにする簡単な方法はありますか?結果は、サークル内に完全に収まる最大のポリゴンでなければなりません。

+2

これはおおよそあなたが探しているものですか:http://ja.wikipedia.org/wiki/Smallest_circle_problem? –

+0

あなたは '倍率** ** **'と言います。これは、XとYのスケーリングが異なる可能性があることを意味しますか?そうでない場合、キャレットの例は明確ではありません。キャレットを左右のポイントが直径の円の左右の端に接触するまでキャレットを拡大すると(その比率を変更することなく)、「トップポイント」の位置は内側にあり、キャレットのアスペクト比 – smirkingman

+0

で定義されているように、エッジまたは外側にあるSimon - それは私が見た最初の本当に有望なリードです。唯一の問題は、ポイントではなくグラフィックパスがあることです。ですから、端点が円内にある大きな曲線があれば、線はそれを通り抜けます。ただし、.Flattenを実行し、平坦化された点を使用して「最小円形アルゴリズム」を実行することは可能です。しかし、1000ポイントから始めると、.Flattenは10kポイントを返します。複雑なアルゴリズムを実行するにはかなりの数があります。 – Flipster

答えて

2

Simonによって発見されたパスではなく、ポイントでこの問題の説明については、http://en.wikipedia.org/wiki/Smallest_circle_problemを参照してください。

  1. したがって、rgnShape.Intersect(rgnCircle);を使用して問題がないかどうかを確認してください。失敗した場合は、各曲線を取得し、見つかった円の中心から最も遠い点を取得します(任意の領域に対して複数の点が存在する可能性があります)。

  2. ポイントリストに追加するとアルゴリズムが再適用されます。最初から始める必要はありません。境界にない点を考慮する必要はありません(つまり、アルゴリズムの元の呼び出しで見つかった「Set Q」にない点を無視する)。

再帰呼び出しを生成する確率はi番目の点のために、もはや1/Iであるので、これは、線形もはやないことに注意してください。

これには明示的に処理する必要があるエッジ条件が1つあります。ステップ1の最初の反復中に見つかった領域の外側に見つかった曲線の1つが完全に円形で外側の円に接触する場合、「Set Q」内に無限の点があり、このアルゴリズムは悲惨に失敗します。したがって、最初にrgnShape.Intersect(rgnCircle);を適用した後は、このケースの明示的に完全な丸い曲線を確認する必要があります。たとえば、(}の場合は、最初の繰り返しで見つかった領域の外側に(がある場合は、()を明示的にチェックする必要があります(ここでは、()は円です)。

これはまだかなり悪いですが、毎回点を点に変更するよりも優れています。

+0

こんにちはブライアン - まだ理想的ではありませんが、私たちはここに近づくことができます。私はそれから始め、そこからいくつかの新しい地面を破ります。あなたはSimonにポイントの半分を与えるべきです、しかし... :-) – Flipster

0

GraphicsPathとRegionでGetBoundsを使用し、四角形のサイズを比較して、少なくとも閉じることができます。

定義されたスペースが正確であるべき正方形である場合。

定義されたスペースが何か他のものなら、それは少なくともあなたを閉じるでしょう。次に、バイナリ検索を使用して実際のスケーリング量を見つけることができます。

+0

これは私が今やっていることとほぼ同じです。私はバイナリサーチを行い、私が「十分に近い」まで各点でサイズを比較していますが、このルーチンは1分に数百回呼び出されます。質問のポイントは、私がより良い解決策を探していることです。 – Flipster

2

バイナリ検索が必要な理由はわかりません。

シェイプの境界矩形が得られ、シェイプに合わせたいターゲット矩形がある場合は、targetHeight/shapeHeighttargetWidth/shapeWidthの2つの比率を比較できます。

より小さい比率を取って、これをスケーリングファクタとして使用してシェイプを拡大/縮小します。

ターゲットが円形であり四角形でない場合は、​​の比率を使用して類似のソリューションを使用し、これを拡大率として使用できます。

+0

応答のためにありがとう、蘭しかし、それもそれをカットしません。非常に単純な例では、低キャレットを私たちの形状( "^")として描きます。円の内側に適切にその形をフィットさせるのは難しいです。そのシェイプ上で.GetBounds()を実行すると、キャレットの上の "点"がサークルの端に実際に移動しないことを意味します。はい、円に四角形を合わせやすいです。しかし、任意の形状を1つに合わせることはずっと困難です...もちろん、 "^"よりもはるかに複雑な形状を扱っています。 – Flipster

0

グラフィックパスの中心と半径を計算できませんか?

重心(座標の平均)を計算し、標準偏差の2倍を追加することができます。これは、グラフの92%を取得する必要があります。ほとんどの場合、グラフは良好ですが、ほとんどの「体重」は片側にあります。

また、すべてのポイントを実行し、boundingboxを計算するときのようにすべての方向に最大/最小ポイントを取得し、これを中心にして最長距離を(最大/最小)ポイント半径。

境界球アルゴリズムを探すともっと洗練されたアルゴリズムが見つかるかもしれませんが、何かを表示するだけの場合はトレードオフを行うことができます。衝突検出を行っている場合は、そのための簡単なアルゴリズムもあります:)

+0

良い提案はありますが、それは「クリーンフィット」である必要があります。コンシューマプロダクト(通常は円や四角形)に任意形状のグラフィックスパスをフィットさせる必要があり、パスをフィッティングするための座標が用意されており、その形状にデザインをフィットさせることが期待されています。それはあなたがそれを試すまで簡単だと思われる。 :-) – Flipster

+0

ああ - 私は参照してください:)長方形のフィッティングは簡単でなければなりません - それは単なるバウンディングボックスです。サークル内ではちょっと難しいですが、実践的です。ポリゴンでフィッティング - おそらくもっと難しい。私はrect、circle、triangleと一般的な多角形に切り替えるでしょう - 最後の多分手のひらや最大の内部rectまたは何か。解決するための楽しい問題のように聞こえます:)あなたのパスにいくつのポイントがありますか? –

+0

こんにちはルーン、良い点(馬鹿を意図していない)。私はグラフィックスパイ上に300〜1200ポイントがあると言っていたはずなので、その数字は些細なものではありません。これらはかなり複雑なパスです。 – Flipster

0

単純な数式を使って逆の方法はありますか?すなわち、パスの境界ボックス/円を取得し、定義済みの高さ/幅の矩形比を計算し、それをBBの同じ値と比較し、それに応じてBBを伸ばします(たとえば、事前定義比率が1未満の場合、BBは水平方向に伸びますそれ以外の場合は同じ比率に一致させる)、最終的にはすべてを事前定義された矩形サイズにスケーリングします。スケールファクタは、定義済みの高さをBBの高さで割った値と、定義済みの幅をBBの幅で割った値の最小値になりました。 (境界円の場合は、サイズを調整する必要はありません)

+0

いくつかの更新を投稿しました。 – Schultz9999

+0

あなたは "パスの境界ボックス/円を取得する"と書いています。シュート。もし私がパスの境界円を得ることができれば、私はやり遂げられるだろう! – Flipster

+0

スケーリング係数を見つけることとは別の問題です。バウンディングボックスは、GetBoundsメソッドを通してあなたに与えられます。私はサークルをチェックします。 – Schultz9999