円弧の端点が正しく描画されない

この記事は、半径が大きい円弧を描画するときに始点と終点が正しい位置に描画されない問題を解決するのに役立ちます。

元の製品バージョン: .NET Framework 3.5 Service Pack 1、.NET Framework 3.5.1、.NET Framework 4.5
元の KB 番号: 2984519

現象

半径が大きい円弧を描画する場合、設定されたパラメータによっては、円弧の始点と終点が正しく描画されない場合があります。

原因

インターネット エクスプローラーなどの Web ブラウザーでは、SVG (スケーラブル ベクター グラフィックス) 形式で表される画像を読み込んで表示する WPF アプリケーションのグラフィックス、または Loose XAML (コンパイルせずにマークアップを読み込んでレンダリングする関数) を使用して画像を表示するアプリケーションを表示できます。

SVG イメージの表示と Loose XAML のレンダリング エンジンでは、DirectX (Direct3D9) が使用されます。

ただし、DirectX (Direct3D9) 内の処理は、単精度浮動小数点数を使用して実行されます。 そのため、処理の制限を超える数を使用すると、予期しない画像が描画される可能性があります。

たとえば、Loose XAML では、マークアップのPathコマンドを使用してA半径が大きい円弧を描画すると、設定する値によっては始点と終点が正しい位置に描画されない場合があります。

状態

この動作は、単精度浮動小数点数を使用して処理を実行するレンダリング エンジンの制限です。

解決方法

開発者は、グラフィックス システムを使用して複雑な描画を実行する場合の数値演算の制限を考慮する必要があります。これは、必ずしも緩やかな XAML に限定されるわけではありません。

半径が大きい円弧を描画する場合は、このような制限のために期待される結果が得られない場合があり、そのような置換の結果の差を合理的に無視できる場合は、円弧を線に置き換えるなどの代替アプローチを取ることをお勧めします。

この問題を再現する手順

マークアップのコマンドを使用して、半径が大きい円弧を描画する場合を再現する手順を A 次に Path 示します。

次のコードを.xaml 拡張子のテキスト ファイルに保存して、緩やかな XAML ファイルを作成します。 インターネット エクスプローラー 11 を使用してこのファイルを開くと、次のスクリーンショットに示すように、WPF レンダリング エンジンによって赤い円弧と青い線が描画されます。

<?xml version="1.0" encoding="utf-8"?>
<Canvas Background="#fff" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Canvas.RenderTransform>
        <TransformGroup>
            <TranslateTransform X="-26000" Y="-3000" />
        </TransformGroup>
    </Canvas.RenderTransform>
    <Path Stroke="#f00" StrokeThickness="1">
        <Path.Data>
            <PathGeometry Figures="M 26557.35, 3320.226 A 1703595, 1703595, 0, 0, 0, 26569.29, 3290.773" />
        </Path.Data>
    </Path>
    <Path Stroke="#00f" StrokeThickness="3">
        <Path.Data>
            <PathGeometry Figures="M 26557.35, 3320.226 L 26569.29, 3290.773" />
        </Path.Data>
    </Path>
</Canvas>

10 行目のコードは、要素内PathGeometryの属性のコマンドによってM設定される絶対座標 (26557.35、3320.226) から別のFigures絶対座標 (26569.29、3290.773) に赤い円弧を描画することを指定します。これは、1703595の半径を使用してコマンドによってA設定されます。

一方、15 行目のコードは、コマンドによって M 設定される絶対座標 (26557.35、3320.226) から別の絶対座標 (26569.29、3290.773) に青い線を L 描画します。

注:

円弧と線の両方で同じ始点と終点のペアが使用されている場合でも、円弧は位置が間違った端点で描画されます。

図は、赤い円弧の端点が誤って配置されていることを示しています。

この例では、半径 170 万ピクセルの円弧を使用して、32 ピクセル離れた 2 つのポイントを接続します。この 2 つの値は天文学的に異なるため、意味のあるアプローチではありません。 次のスクリーンショットに示すように、線 (AMB) からの円弧 (AM'B) の最大偏差は 0.0001 ピクセル (MM') 未満です。これは、それらの図形が最大限の数学的精度で描画された場合でも見えないほど小さくなります。 したがって、このような状況では、内部処理の数値制限に達する可能性が低くなるため、これら 2 つのポイント間に線を引く方がはるかに好ましい方法になります。

図は、線からの円弧の最大偏差を示しています。