メイン・コンテンツまでスキップ

Canvas Widget(キャンバス・ウィジェット)

Canvas WidgetとCanvas Widget Rendererは、強力で用途の広いTouchGFXのアドオンで、相対的に少ないメモリ使用量で高パフォーマンスを維持しながら、幾何学形状に対して非常に滑らかでアンチエイリアスされた描画を実現します。 ただし、幾何学形状の描画は極めて負荷の高い操作ですので、注意して使用しないとマイクロコントローラのリソースが簡単にひっ迫することになります。

Canvas Widget Renderer(以下、CWR)は一般的なグラフィックAPIで、プリミティブな最適化された描画を実現し、ほとんどの不要な描画を自動的に除去してくれます。 TouchGFXは、複雑な幾何学形状の描画にCWRを使用します。 幾何学形状はCanvas Widgetによって定義されます。 TouchGFXには多くのCanvas Widgetがサポートされていますが、通常のウィジェットと同様に、ユーザのニーズに合わせて独自のカスタムCanvas Widgetを作成することができます。 CWRが描画する図の幾何学形状をCanvas Widgetが定義するとき、図の中の各ピクセルの実際の色が、関連付けられたPainterクラスによって定義されます。 この場合も、TouchGFXには多数のPainterが用意されていますが、ユーザのニーズに合わせて独自のカスタムPainterを作成することができます。

キャンバス・ウィジェット(Canvas Widget)の使用

TouchGFXにある他のウィジェットは、サイズが自動的に設定されます。 たとえば、ビットマップ・ウィジェットは、含まれているビットマップの幅と高さを自動的に取得します。 このため、ビットマップ・ウィジェット上でsetXY()を使用して、ビットマップを画面上に配置するだけで十分です。

Canvas Widgetには、自動的に決められ初期設定されるデフォルト・サイズがありません。 ウィジェットを配置するだけでなく、正しくサイズ設定するように注意する必要があります。そうでないと、Canvas Widgetの幅と高さはゼロになり、画面上に何も描画されなくなります。

したがって、setXY()を使用する代わりにsetPosition()を使用してCanvas Widgetの配置とサイズ設定を行います。 カスタムCanvas Widgetを作成して使用する方法については、下にある例「カスタムCanvas Widget」を参照してください。

Canvas Widgetの位置とサイズを設定した後は、その中に幾何学形状を描画できます。 ウィジェット(画面ではない)の左上隅の座標が(0, 0)になり、X軸は右方向に、Y軸は下方向に伸びます。

Canvas WidgetはTouchGFX Designerでもサポートされ、使い勝手がよくなり、メモリの計算やメモリの割り当てが自動的に行われます。

TouchGFX Designerで使用可能なキャンバス・ウィジェット

TouchGFX Designerでこれらのウィジェットを使用すると、実行時のウィジェットの見え方が示されるので、配置やサイズ調整がはるかに容易になります。

メモリ割当てと使用量

うまくアンチエイリアスされた複雑な幾何学形状を生成するには、追加のメモリが必要です。 このためCWRには、描画時に使用される特別に割り当てられたメモリ・バッファが必要です。 TouchGFXのその他の部分と同様に、CWRでは動的なメモリ割り当ては行われません。

TouchGFX Designerでのメモリ割当て

スクリーンのキャンバスにウィジェットを追加すると、メモリ・バッファが自動的に生成されます。 バッファのサイズは、スクリーンの幅に基づき、(幅 × 3)× 5という式を使用して決められます。 ただしこれは、すべてのシナリオに対して常に最適なバッファ・サイズではありません。 このため、下記の画像に示すように、バッファ・サイズをオーバーライドできます。

スクリーンのプロパティでオーバーライドされるキャンバスのバッファ・サイズ

Note
上記のオーバーライド機能を使用して、キャンバス・ウィジットを使用しないスクリーンにメモリ・バッファを生成することもできます。 これはユーザ・コードでキャンバス・ウィジットを作成する場合に便利です。

ユーザ・コードでのメモリ割当て

キャンバス・ウィジットを使用するスクリーンに、TouchGFX Designerを使用しないでメモリ・バッファを割り当てる場合は、バッファを手動で設定する必要があります。 設定には、Screen::setupScreenメソッドの使用を推奨します。

以下をプライベート・メンバーとしてScreenクラスの定義に追加します。

private:
static const uint16_t CANVAS_BUFFER_SIZE = 3600;
static uint8_t canvasBuffer[CANVAS_BUFFER_SIZE]

次に、ScreenView.cppsetupScreen()メソッドに、バッファを設定する以下の行を追加します。

void ScreenView::setupScreen()
{
...
CanvasWidgetRenderer::setupBuffer(canvasBuffer, CANVAS_BUFFER_SIZE);
...
}

さらに、ScreenView.hppのデストラクタ~ScreenView()に、バッファをリセットする次の行を追加します。

virtual ~ScreenView()
{
touchgfx::CanvasWidgetRenderer::resetBuffer();
}

CWRの必要なメモリ量は、アプリケーションで描画する形状の最大サイズに応じて異なります。 ただし、最も複雑な形状が必要とするメモリ量より少なく抑えることができます。 この状況に対処するため、CWRは描画の形状を小さいフレームバッファ・パーツに分割します。この結果、描画時間は少し長くなります。これは、ときには形状を描画するのに1回ではすまないことがあるからです。 シミュレータ・モードで実行すると、メモリ消費量を綿密に調べて微調整することができます。 main.cppに次の関数呼び出しを追加するだけです。

CanvasWidgetRenderer::setWriteMemoryUsageReport(true);

これで、描画操作が終了するたびに、必要とされたメモリ量をCWRがレポート(コンソールで出力)するようになります。 canvas_widget_exampleの場合は、“CWR requires 3604 bytes”(最初の描画操作時に)の後に、“CWR requires 7932 bytes (4328 bytes missing)”(2回目の描画操作時に)が続くことになります。 CWRのメモリ量は十分でないように見えますが(この例では4328バイト欠落)、アプリケーションは正常に実行されます。 これは、1回の実行で複雑な描画操作を完了するには、使用可能なメモリの量が少なすぎることをCWRが検出したからです。 代わりに、CWRは描画操作を2つの別々の描画操作に分割するので、形状の描画は問題なく行われますが、描画に時間がかかることになります。

したがって、正しいメモリ・バッファ・サイズの設定は、メモリとパフォーマンス(描画時間)の間のトレードオフなのです。 通常の適切な開始値は3000前後ですが、上記の技法を使用すると、もっと適した値を設定できることが多くなります。 形状が複雑すぎて、割り当てられたメモリ・バッファがあまりにも小さすぎる場合は、形状の一部が描画されません(一部の垂直ピクセル・ラインがスキップされます)。また、何も描画されない可能性もあります。 いずれにせよ描画時間は非常に長くなります。

つまり、アプリケーションでCWR描画を最大速度で描画する場合には、要求されたメモリ量を割り当てる必要があるということです。 ただし、描画時間が長くかかっても構わない場合は、メモリ・バッファを減らしてもまったく問題ありません。

CWRの座標系

通常、TouchGFXの座標系は、画面上にビットマップを配置するためのピクセル処理に使用されます。 ビットマップ、テキスト、その他のグラフィック要素はすべて座標系に配置されます。ここでは(0,0)が左上のピクセルで、X軸は右方向に、Y軸は下方向に伸びます。 CWRでは、整数を使用してピクセルを十分に処理することはできません。特殊なケースでは十分なこともありますが、一般的にとても十分とは言えません。 この例を示すため、線幅が1の円について考えてみます。この円を5 x 5ピクセルのボックス内にぴったりと収める必要があるとします。 この円の中心は(2.5, 2.5)にし、半径は2にする必要があります(ラインは円周の両側に0.5幅で描画されます)。そのため、中心座標には小数部が必要です。 同様に、この円を6 x 6ピクセルのボックス内に収める場合には、中心を(3, 3)にして半径を2.5にする必要があります。今度は半径に小数部が必要になります。

グラフィックス描画のためのこの新しい座標処理方法は、(0,0)にあるピクセルの中心のCWR座標は(0.5, 0.5)になることを意味しています。 したがって、スクリーンの左上隅のピクセルを含むボックスのアウトライン座標は、(0,0) -> (1,0) -> (1,1) -> (0,1) -> (0,0)になります。

(0,0)にあるピクセルのCWR座標系

この処理方法に最初は戸惑うかもしれませんが、すぐに非常に自然なものになります。 ビットマップの座標系でピクセルを処理する場所では、Canvas Widgetの同じ座標でピクセルの直前と上のギャップを処理します。

円は、中心を正しく配置するために0.5ピクセル移動する必要がよく生じる形状なので、関数Circle::setPixelCenter()は、円の中心を指定のピクセルの中心に配置、つまり、指定された座標よりも0.5ピクセル右および下に配置します。

カスタムCanvas Widget

カスタムCanvas Widgetを実装するには、次の関数を使用して新しいクラスを実装する必要があります。

virtual bool drawCanvasWidget(const Rect& invalidatedArea) const;
virtual Rect getMinimalRect() const;

drawCanvasWidget()ではカスタム・ウィジェットが描画する必要のあるものすべてを描画する必要があり、getMinimalRect()は、幾何学形状を格納するウィジェット内に実際の長方形を返します。

Note
**分節不備** getMinimalRect() を使用する理由は、幾何学形状がそのウィジェット内を動き回ることができるからです。また、多くの場合、ごくわずかな領域を無効化するためだけに形状を変更するたびに、ウィジェットのサイズ変更や再配置を行うのは実用的ではありません。
<InlineCode>getMinimalRect()</InlineCode> のダミー実装では、単純に <InlineCode>return rect;</InlineCode>を使用すればよいのですが、返されるのはウィジェットのサイズです。ただし、幾何学形状を含むCanvas Widgetの部分だけでなく、Canvas Widgetによってカバーされる領域全体が再描画されることになります。 ほとんどの場合、幾何学形状はCanvas Widgetのほんの一部分しか占有しません。

Canvas WidgetはすべてCanvasクラスを使用します。これは前述のように、Canvas Widget Rendererをカプセル化するものです。 CWRには多くの最適化が自動的に適用されますが、無効化された領域に関連する幾何学形状を認識し、無効化領域外の不要な描画を避けることは、常にパフォーマンス向上のための早道になります。

10x10のボックス内に、ひし形の正方形を大まかに実装する方法は以下のようになります。

#include <touchgfx/widgets/canvas/CanvasWidget.hpp>
#include <touchgfx/widgets/canvas/Canvas.hpp>

using namespace touchgfx;

class Diamond10x10 : public CanvasWidget
{
public:
virtual Rect getMinimalRect() const
{
return Rect(0,0,10,10);
}
virtual bool drawCanvasWidget(const Rect& invalidatedArea) const
{
Canvas canvas(this, invalidatedArea);
canvas.moveTo(5,0);
canvas.lineTo(10,5);
canvas.lineTo(5,10);
canvas.lineTo(0,5);
return canvas.render(); // Shape is automatically closed
}
};
Note
再び、 getMinimalRect() が正しい長方形を返すかどうか確認します。そうでないとスクリーン上のグラフィックスが正しく表示されない可能性があります。

Diamond10x10をディスプレイに表示するために、Painterをひし形に渡して、色を設定する必要があります。 Painterの詳細については、次のセクションを参照してください。 さらに、Diamond10x10を正しく配置してサイズ設定する必要もあります。 これは次のような設定になります。

ヘッダ・ファイルで次のように宣言します。

Diamond10x10 box;
PainterRGB565 myPainter; // For 16bpp displays

また、コードでは、setupScreen()に次のような記述が必要です。

myPainter.setColor(Color::getColorFromRGB(0xFF, 0x0, 0x0));
box.setPosition(100,100,10,10);
box.setPainter(myPainter);
add(box);

Painter(ペインタ)

Painterは、Canvas Widgetオブジェクトを塗りつぶすためのカラー・スキームを定義するもので、形状を表示するために必要になります。 Painterでは、すべてのピクセルに1つの色を提供したり(PainterRGB565など)、提供されたビットマップから各ピクセルをコピーしたりできます(PainterRGB565Bitmapなど)。 Painterはフレームバッファにピクセルを直接書き込むため、選択したPainterはフレームバッファまたはダイナミック・ビットマップのフォーマットに一致する必要があります。 TouchGFXには、塗りつぶし色、またはビットマップの描画に特化したPainterなど、サポートされたすべてのディスプレイ用のPainterが用意されています。

Painterクラス

次の表に、TouchGFXで利用可能なPainterを示します。 キャンバス・ウィジェットをTouchGFX Designer上で使用する場合は、Designerによって適切なPainterが選択されますが、キャンバス・ウィジェットを使用するコードを自分自身で記述する場合は、適切なPainterを選択する必要があります。

フレームバッファのフォーマットカラーPainterビットマップPainter
BWPainterBWPainterBWBitmap
GRAY2PainterGRAY2PainterGRAY2Bitmap
GRAY4PainterGRAY4PainterGRAY4Bitmap
ABGR2222PainterABGR2222PainterABGR2222Bitmap
ARGB2222PainterARGB2222PainterARGB2222Bitmap
BGRA2222PainterBGRA2222PainterBGRA2222Bitmap
RGBA2222PainterRGBA2222PainterRGBA2222Bitmap
RGB565PainterRGB565PainterRGB565Bitmap、PainterRGB565L8Bitmap
RGB888PainterRGB888PainterRGB888Bitmap、PainterRGB888L8Bitmap
ARGB8888PainterARGB8888PainterARGB8888Bitmap、PainterARGB8888L8Bitmap
XRGB8888PainterXRGB8888PainterXRGB8888Bitmap、PainterXRGB8888L8Bitmap

ビットマップPainterは各種ビットマップ・フォーマットに対応しています。

Painterサポートされているビットマップ・フォーマット
PainterBWBitmapBW、BW_RLE
PainterGRAY2BitmapGRAY2
PainterGRAY4BitmapGRAY4
PainterABGR2222BitmapABGR2222
PainterARGB2222BitmapARGB2222
PainterBGRA2222BitmapBGRA2222
PainterRGBA2222BitmapRGBA2222
PainterRGB565BitmapRGB565、ARGB8888
PainterRGB565L8BitmapL8_RGB565、L8_RGB888、L8_ARGB8888
PainterRGB888BitmapRGB888、ARGB8888
PainterRGB888L8BitmapL8_RGB565、L8_RGB888、L8_ARGB8888
PainterARGB8888BitmapRGB565、RGB888、ARGB8888
PainterARGB8888L8BitmapL8_RGB565、L8_RGB888、L8_ARGB8888
PainterXRGB8888BitmapRGB565(透明度なし)、RGB888、ARGB8888
PainterXRGB8888L8BitmapL8_RGB565、L8_RGB888、L8_ARGB8888

タイル化されたビットマップ

ビットマップからピクセルを描画するPainterは、キャンバス・ウィジェットの左上隅にビットマップを配置します。 ビットマップ・ディメンション外にある形状のピクセルは描画されません。

ビットマップPainterは、形状全体を網羅するためにウィジェット(タイル化)を繰り返し実行するように設定できます。

タイル化は、Painter上でsetTiled(bool)メソッドを呼び出すと、有効になります。

    PainterRGB888Bitmap bitmapPainter;
...
bitmapPainter.setBitmap(touchgfx::Bitmap(BITMAP_BLUE_LOGO_TOUCHGFX_LOGO_ID));
bitmapPainter.setTiled(true);

タイル化は、Designerでは有効にできません。

画像、ビットマップPainterによる円、タイル化ビットマップPainterによる円を表示するアプリケーション。

カスタムPainter

TouchGFXには、ほとんどのユース・ケース・シナリオを網羅する一連のPainterクラスが事前に定義されていますが、カスタムPainterも実装できます。

このセクションでは、ヒントとして使用できる、いくつかの例を紹介します。 これらの例は16bpp RGB565用のみです。 それ以外のフレームバッファ・フォーマットには、少し変更を加える必要があります。

カスタムPainterはAbstractPainterクラスのサブクラスです。 16bpp(RGB565)フレームバッファ用Painterは、AbstractPainterRGB565クラスをスーパークラスとして使用できます。 24bpp(RGB888)フレームバッファ用Painterは、AbstractPainterRGB888クラスをスーパークラスとして使用できます。

これらのスーパークラスは抽象クラスです。 カスタムPainterクラスは次のメソッドを実装する必要があります。

    virtual void paint(uint8_t* destination, int16_t offset, int16_t widgetX, int16_t widgetY, int16_t count, uint8_t alpha) const = 0;

destinationは、フレームバッファの開始位置(ウィジェットの左端)を示しています。
offsetは、この開始位置から最初のピクセルを配置するまでのピクセル数です。
widgetX、widgetYは、ウィジェットを基準にした最初のピクセルの座標です(フレームバッファ座標系で指定)。
countは、指定のalphaで描画されるピクセル数です。

キャンバス・ウィジェットはこのメソッドを何度も呼び出すため、Paintの実装に時間がかからないことが大変重要です。 キャンバス・ウィジェットが頻繁に更新されない場合は、これはさほど重要ではありません。

カラーPainter

最も単純なPainterは、フレームバッファに固定カラーを書き込むだけです。 その実装方法は次のとおりです。

#include <touchgfx/widgets/canvas/AbstractPainterRGB565.hpp>
using namespace touchgfx;
class RedPainter : public AbstractPainterRGB565
{
public:
virtual void paint(uint8_t* destination, int16_t offset, int16_t widgetX, int16_t widgetY, int16_t count, uint8_t alpha) const
{
uint16_t* framebuffer = reinterpret_cast<uint16_t*>(destination) + offset; // Address of first pixel to paint
const uint16_t* const lineend = framebuffer + count; // Address of last pixel to paint
const uint16_t redColor565 = 0xF800; // Full red in RGB565
do
{
*framebuffer = redColor565;
} while (++framebuffer < lineend);
}
};

Painterのインスタンスを作成し、それをキャンバス・ウィジェットに割り当てることを忘れないでください。 Painterタイプのメンバーをクラスに追加します

Circle myCircle;
RedPainter myPainter;

また、コードでは、setupScreen()に次のような記述が必要です。

...
myCircle.setPainter(myPainter);
...

円をペイントするRedPainter。 右側に表示されているのは拡大部分です。

上記のRedPainterクラスはアルファ・パラメータを無視します。 これにより、 すべてのピクセルが完全に赤色になるため、エッジが粗くなります(アルファブレンディングなし)。 この状態を、必要に応じて若干のコードを更新し、アルファ・パラメータを使用してブレンディングを行なうよう改善できます。

#include <touchgfx/widgets/canvas/AbstractPainterRGB565.hpp>
using namespace touchgfx;
class AlphaRedPainter : public AbstractPainterRGB565
{
public:
virtual void paint(uint8_t* destination, int16_t offset, int16_t widgetX, int16_t widgetY, int16_t count, uint8_t alpha) const
{
uint16_t* framebuffer = reinterpret_cast<uint16_t*>(destination) + offset; // Address of first pixel to paint
const uint16_t* const lineend = framebuffer + count;
const uint16_t redColor565 = 0xF800; // Full red in RGB565
do
{
if (alpha == 0xFF)
{
*framebuffer = redColor565; // Write red to framebuffer
}
else
{
*framebuffer = alphaBlend(redColor565, *framebuffer, alpha); // Blend red with the framebuffer color
}
} while (++framebuffer < lineend);
}
};

AlphaBlend関数は、2つのRGB565ピクセルを、最初のピクセルに指定されたアルファ係数を使用してブレンディングします。 この関数は、スーパークラスAbstractPainterRGB565によって提供されます。 円のエッジはこのコードで滑らかになります。

円をペイントするRedAlphaPainter。 右側に表示されているのは、アルファブレンディングの効果を示す拡大部分です。

WidgetXおよびWidgetYパラメータは、特定の領域への描画を制限するために使用できます。 ここに、1行おきの水平ラインにのみペイントするPainterの例を示します。 WidgetYはその制御に使用されます。

#include <touchgfx/widgets/canvas/AbstractPainterRGB565.hpp>
using namespace touchgfx;
class StripePainter : public AbstractPainterRGB565
{
public:
virtual void paint(uint8_t* destination, int16_t offset, int16_t widgetX, int16_t widgetY, int16_t count, uint8_t alpha) const
{
if ((widgetY & 2) == 0)
{
return; // Do not draw anything on line 0,1, 4,5, 8,9, etc.
}
uint16_t* framebuffer = reinterpret_cast<uint16_t*>(destination) + offset;
const uint16_t* const lineend = framebuffer + count;
if (alpha == 0xFF)
{
do
{
*framebuffer = 0xF800;
} while (++framebuffer < lineend);
}
else
{
do
{
*framebuffer = alphaBlend(0xF800, *framebuffer, alpha);
} while (++framebuffer < lineend);
}
}
};

円をペイントするStripePainter。 右側に表示されているのは拡大部分です。

フレームバッファの変更

このセクションのPainterは、フレームバッファに対して特定のコンテンツをペイントすることはありませんが、フレームバッファをグレースケールに変更します。 これは、フレームバッファのピクセル値(円のバックグラウンドにあるウィジェットによって書き込まれた)を読み取ることで実行され、緑のコンポーネントを抽出し、これを使用して灰色(赤、緑、青の値が同じ)を作成し、フレームバッファに書き戻します。

フレームバッファの読み取りと変更に関するこの原則を使用して、多くの類似する技法を開発できます。

#include <touchgfx/widgets/canvas/AbstractPainterRGB565.hpp>
#include <touchgfx/Color.hpp>
using namespace touchgfx;
class GrayscalePainter : public AbstractPainterRGB565
{
public:
virtual void paint(uint8_t* destination, int16_t offset, int16_t widgetX, int16_t widgetY, int16_t count, uint8_t alpha) const
{
uint16_t* framebuffer = reinterpret_cast<uint16_t*>(destination) + offset;
const uint16_t* const lineend = framebuffer + count;
do
{
const uint8_t green = Color::getGreenFromRGB565(*framebuffer) & 0xF8; // Keep only 5 bits of the green
const uint16_t color565 = LCD16bpp::getNativeColorFromRGB(green, green, green);
if (alpha == 0xFF)
{
*framebuffer = color565;
}
else
{
*framebuffer = alphaBlend(color565, *framebuffer, alpha);
}
} while (++framebuffer < lineend);
}
};

左側: 元のバックグラウンド。 右側: Circular Painterが円内部のピクセルをグレースケールに変更。

回転したディスプレイ上のカスタム・コンテナ

アプリケーションで回転したディスプレイを使用している場合、カスタム・コンテナのコードでは、これを考慮する必要があります(ただし、ペイントで座標が使用されている場合)。

次に、回転したディスプレイで使用されるStripePainterを示します。

円をペイントするStripePainter。 右側に表示されているのは拡大部分です。

画像、テキスト、ボタンはTouchGFXエンジンによって回転されましたが、ストライプはテキストに対して垂直になっていることがわかります。これは平行になっているべきものです。 つまり、ラインは回転されませんでした。
問題はフレームバッファが回転されないことです。そのため、Painterが連続したアドレス(フレームバッファのピクセル)にペイントすると、ラインは以前と同じ向きになります(回転しません)。

これは、WidgetXを使用してペイントしているかどうかを判断することで修正できます。 widgetXおよびwidgetYパラメータは、フレームバッファ座標系で指定されます。 つまり、widgetXは、ディスプレイを下方に移動すると増加し、ディスプレイの座標系ではy座標に一致することを意味します。★

#include <touchgfx/widgets/canvas/AbstractPainterRGB565.hpp>
#include <touchgfx/Color.hpp>
using namespace touchgfx;
class StripePainterRotate90 : public AbstractPainterRGB565
{
public:
virtual void paint(uint8_t* destination, int16_t offset, int16_t widgetX, int16_t widgetY, int16_t count, uint8_t alpha) const
{
uint16_t* framebuffer = reinterpret_cast<uint16_t*>(destination) + offset;
const uint16_t* const lineend = framebuffer + count;
if (alpha == 0xFF)
{
do
{
if (widgetX++ & 2)
{
*framebuffer = 0xF800;
}
} while (++framebuffer < lineend);
}
else
{
do
{
if (widgetX++ & 2)
{
*framebuffer = alphaBlend(0xF800, *framebuffer, alpha);
}
} while (++framebuffer < lineend);
}
}
};

これで、ストライプが正しい向きになりました。

円をペイントするStripePainterRotate90。

フィル・ルール

Shapeウィジェットでは、Fill-Non-ZeroまたはFill-Even-Oddという2つのフィル・ルールのいずれかを選択できます。 Fill-Non-Zeroルールがデフォルトのルールです。 次に示す2つの図は、2つのフィル・ルールの違いを示しています。

Fill-Even-Oddルールを使用してペイントした星形

Fill-Non-Zeroルールを使用してペイントした星形

Even-Oddルールでは、偶数(ここではゼロまたは2)のエッジとクロスすることで外側から到達できるピクセルはペイントされません。

Non-Zeroルールでは、ピクセルへのパス上で左から右向きにエッジの数がカウントされ、右から左向きにエッジの数が減算されます。 カウントが非ゼロになれば、ピクセルがペイントされます。

フィル・ルールはコードで簡単に設定できます。

    touchgfx::Shape<5> shape1;
....
shape1.setFillingRule(Rasterizer::FILL_EVEN_ODD);