@soramimi_jpです。
Twitterとブログにも書いたのですが、
下記のような、
QRectF a(0, 0, 40, 40); QRectF b(10, 20, 20, 0); bool f = a.contains(b);
幅または高さがゼロの矩形に対するcontainsがfalseを返します。 QRectFではなくQRectにするとtrueが返ります。 Qt5.3.1です。
なぜだかわかる方いらっしゃいますか?
小澤です。
度々の連投、申し訳ありません。
androidのアプリをQt5.3.2で作成しています。 ubuntuにてQtCreatorとandroid sdk、android ndk、antをインストールして、一度は、エミュレータのandroidにアプリがデプロイするところを確認しています。 その後、QtCreatorのGCCのパスが通ってなかったため、GCC4.9.2をビルド・インストールした後、デスクトップ環境でアプリを作成していました。 アプリが完成したので、エミュレータ上で起動させようとandroid側で動作させようとしたのですが、AVD Managerが起動しませんでした。 android-sdkは最初にデプロイさせたときから特に変更していないのですが、なぜ起動しないのでしょうか?
そらみみさん、こんにちは。ケイロニアンです。
ちょろっとQtのソースみてみました。 QRectのソースはqtbase\src\corelib\tools\qrect.cppにありました。 (5.4.0を見ています。)
QRect::contains()は頭でisNull()ならfalseを返却してます。 isNull()の定義は(left==right) 【&&】 (top==bottom)ですから、そらみみさ んのソースの場合、isNull()に該当しないのでfalseは返らないでOKですね。 しかし、QRectF::contains()は、処理の途中で(left==right)、【もしくは】、 (top==bottom)になった時に、falseを返却しています。 そらみみさんのソースの場合、この条件に該当するのでfalseが返ることにな りますね。 つまり、Qtのソース的にQRectではtrue、QRectFではfalseとなっていると思い ます。
同じ名前の関数の動作が異なるのは違和感が強いです。 QRectFの上記条件判断しているところに、"null rect"ってコメントされてま す。でも、この条件はisNull()ではなくisEmpty()と同じだと思います。 (emptyは空の容器で、nullは容器ごと無いなんてイメージかも?)
私はまだQt始めたばかりですので、ちょっと心配です。他の方のご意見もご確 認下さいね。
以上
PS.小澤さん ごめん。私はAndroidは大昔触ったっきりでもう覚えていません。解る方が来 られるのをお待ちくださいな。
ケイロニアンさん、こんにちは。@soramimi_jpです。
なるほど、わかりません(笑)
図形編集ソフト(Illustrator的な何か)を作っていまして、 矩形選択ツールを選んでから、図形を囲むようにドラッグしたときに、 その中に含まれている図形に対して処理を行う、といった機能を実装 してるんですけど、幅か高さがゼロの図形が選択から漏れてしまう という問題が発覚して、「containsの再発明」をすることにしました。
ソフトの都合上、QRectF(0, 0, 0, 0)がQRectF(-1, -1, 2, 2)の内部に 含まれてくれないと困るので、自作関数で対処しようと思います。
QRect/QRectFのisNull()とisEmpty()って、そういうメンバ関数があるのは 知っていましたが、どういう挙動をするか確信が持てず、ソース読んでも どうせすぐ忘れるし、結果の予想ができないので、不安で使えないです。
@soramimi_jpさん、こんばんは。ケイロニアンです。
なるほど、わかりません(笑)
あは。
という問題が発覚して、「containsの再発明」をすることにしました。
ソフトの都合上、QRectF(0, 0, 0, 0)がQRectF(-1, -1, 2, 2)の内部に 含まれてくれないと困るので、自作関数で対処しようと思います。
たぶん、それしかないと思います。
QRectF(0, 0, 0, 0)だけでなく QRect(0, 0, 0, 0)も、QRectF(-1, -1, 2, 2)、 QRect(-1, -1, 2, 2)には含まれない筈ですから。
してるんですけど、幅か高さがゼロの図形が選択から漏れてしまう
幅か高さのどちらかがゼロの矩形はEmptyっす。この矩形は線分になります。 幅と高さの 両方 がゼロの矩形はNull っす。この矩形は点になります。
QRectFとQRectの両方とも、Nullの矩形(点)が他の矩形に含まれることはない ようです。 QRectFはEmpty(線)の時も含まれないという振る舞いがQRectと異なってます。
因みに、文字列の場合、Emptyは""で、NullはNULLですね。似ているような違 うような...
ではでは
忘年会続きで体調不良のhermit4です。途中まで調べて、おつきあいが忙しく なって、亀レスになってしまいました。
QRect/QRectFにおいて、高さあるいは幅が0の場合はinvalidな扱いですので、 どうなるのが正しいのかは悩ましい所です。QRectとQRectFの結果が不一 致なのは違和感があるというのはその通りですけど。
ドキュメントではQRectとQRectFで、Emptyに対する説明が異なっています。
QRectF::isEmpty() function returns true if the rectangle's width or height is less than, or equal to, 0.
QRect::isEmpty() function returns true if left() > right() or top() > bottom().
この通りに実装されるとしたら、QRectFの場合は、高さあるいは幅が0の 場合はEmpty で、QRectの場合は、0の場合でもemptyは成立しないように も感じて、これが理由かなとも思ったのですが・・・。
qDebug() << "QRect is empty : " << QRect(10,10,10,0).isEmpty(); qDebug() << "QRect is valid : " << QRect(10,10,10,0).isValid(); qDebug() << "QRectF is empty : " << QRectF(10,10,10,0).isEmpty(); qDebug() << "QRectF is valid : " << QRectF(10,10,10,0).isValid();
QRect is empty : true QRect is valid : false QRectF is empty : true QRectF is valid : false
ということで、想像と違っていました・・・。
おそらく、当初は、QRectFをQRectにアラインした場合に、オリジナルの QRectF時の結果と返還後のQRectで結果が異なるケースを恐れての差分が あったのかとも思うのですが、ともあれソースコードを読むと、double (qreal)が==演算子で比較されていたり、話題にもなっているempty rectと 書くべきコメントがnull rectとしてコメントされていたりと、適当に書い たバグ込みのコードの臭いがぷんぷんしています。
本件は、過去にバグレポートもされていたようですが、実際、この手の ものは直すと多くのアプリケーションを壊す可能性があり変更できない という理由でCloseされているようです。
https://bugreports.qt-project.org/browse/QTBUG-18719
whether zero sized rect should be considered being inside other rects is a question with many right answers However either way we cannot change the behavior as it will most likely break a lot of application.
鈴木さんによると、「最近の傾向だと、直せないなら代替メソッドを作っ て緩やかにそっちに移行していくように仕向ける感じ?」との事なので、 再度reopenして、対処を提案したとしても、直るまでにはしばらく時間 がかかりそうな気がします。
@soramimi_jpです。
もしかして、と思って試してみました。unitedです。ソースは確認していません。
QRectF a(100, 100, 1, 1); QRectF b(200, 200, 1, 1); QRectF c = a.united(b);
上の例では、QRectF(100, 100, 101, 101)が返ります。 それはいいのですが、
QRectF a(100, 100, 1, 1); QRectF b(200, 200, 0, 0); QRectF c = a.united(b);
↑だと、aがそのまま返る。 (希望としてはQRectF(100, 100, 100, 100)が返ってほしい)
QRectF a(100, 100, 0, 0); QRectF b(200, 200, 1, 1); QRectF c = a.united(b);
↑だと、bがそのまま返る。 (希望としてはQRectF(100, 100, 101, 101)が返ってほしい)
単純に、座標の値だけに基づいて結果を返して欲しいんですが、 NullとかEmptyが余計なお節介をしているようです。
isNullもisEmptyもcontainsもintersectsもunitedも全部obsoleteにてくれないかな。
たすくです。
isNullもisEmptyもcontainsもintersectsもunitedも全部obsoleteにてくれないかな。
そういうパッチを送ってみるか、
(https://bugreports.qt-project.org/browse/QTBUG-18719 の理由も分かるけど) QRect と QRectF で挙動が違うのはおかしいよね?
って開発者のメーリングリストで聞いてみるのはいかがでしょうか。
個人的には QRectangle(F) クラスを作って、Qt の中で QRect(F) を使っているコードを全部 QRectangle(F) に置き換えて で QRect(F) を非推奨にするのがいいかなぁと思います。
こんにちは。ケイロニアンです。
ドキュメントではQRectとQRectFで、Emptyに対する説明が異なっています。
私も最初はこれかと思いました。でも、説明は異なってますが、仕様的には同 じでした。何言ってるか分かりませんね。(汗)
大昔、サブピクセル?なにそれ美味しいの?って時代は、矩形を左上コーナー の座標と右下コーナーの座標で定義することが多かったです。右下も矩形内部の 座標として定義してましたので、width=right-left+1となります。
説明を見るとQRectもこの定義になっているようです。確かどこかに「歴史的 理由」って書かれていたので、分かっちゃいるけど、もう直せないってやつと思 います。 QRectのempty条件left > rightは、width=right-left+1なので、変形すると
0 > right-left 0 > width-1 1 > width
widthは整数なので、
0 => width
となり、QRectFの条件と一致するのですよ!! 右下コーナー座標を矩形の中に含めたことを激しく後悔する瞬間です。
*
個人的には QRectangle(F) クラスを作って、Qt の中で QRect(F) を使っている コードを全部 QRectangle(F) に置き換えてで QRect(F) を非推奨にするのが いいかなぁと思います。
realとintの差だけなら、templateで定義できたらかっこいいですね!! QRectFをコピペして、そらみみさんの思いを込めて修正し、公開してみれば、 採用されたりして。 Qt初心者の私が言うのはおこがましいですが、isNullって必要性が見えない割 に混乱するし、contains等でNullやEmptyチェックはしない方が良いと私も思い ます。(需要がある以上、よりプリミティブな関数も提供した方が良いので。)
以上