4.計算インターフェースモジュールの設計と実装
線のそのセグメント内の私のユニークが基本的に新機能の実現の元の線形相関関数への呼び出しであり、直線セグメントは、第一光線の交点を計算する際、またはその中にそれらが配置され、そして計算される直線との交点を決定します点は、線分または放射線にあるかどうか、大幅にコード・ロジックを簡素化します。
幾何学オブジェクトが格納されたデータのみをカプセル化することを考えると、この方法は、構造体と、従ってパッケージ形状を伴いません
struct Point {//点
double x;
double y;
double length;
bool operator ==(const Point& b) const noexcept
{
if (compareDouble(x - b.x) == 0 && compareDouble(y - b.y) == 0) return true;
return false;
}
bool operator <(const Point& b) const noexcept
{
if (compareDouble(x - b.x) == 0 && compareDouble(y - b.y) < 0) return true;
if (compareDouble(x - b.x) < 0) return true;
return false;
}
};
typedef Point Vector; //向量
struct Line { //直线
Point p1, p2;
};
struct Segment { //线段
Point p1, p2;
};
struct Ray { //射线
Point start, direction;
};
struct Circle { //圆
Point center;
double r;
};
コマンドラインハンドラは、入力と出力ファイルの名前を取得します。同じベクターに入力ファイル、幾何オブジェクトの同じ種類からすべての幾何学的なオブジェクトを取得します。すべての交差点Point
に集合set
。
vector<Line> lineSet;
vector<Segment> segmentSet;
vector<Ray> raySet;
vector<Circle> circleSet;
set<Point> pointSet;
ポイント算出交差点calPoint
機能又は内部ベクターで同じベクター内の2つの異なるクラスの間です。交点演算getPoint
2つの幾何学的オブジェクト間の機能、交差点の数を算出返さ:NOCROSS
、、 、ONECROSS
(TWOCROSS
多数のMANYCROSS
交差点)。
次のように定義された交点計算機能
int getPoint(Line l1, Line l2, Point& crossPoint) noexcept;
int getPoint(Line l, Segment s, Point& crossPoint) noexcept;
int getPoint(Line l, Ray r, Point& crossPoint) noexcept;
int getPoint(Line l, Circle c, pair<Point, Point>& crossPair) noexcept;
int getPoint(Segment s1, Segment s2, Point& crossPoint) noexcept;
int getPoint(Segment s, Ray r, Point& crossPoint) noexcept;
int getPoint(Segment s, Circle c, pair<Point, Point>& crossPair) noexcept;
int getPoint(Ray r1, Ray r2, Point& crossPoint) noexcept;
int getPoint(Ray r, Circle c, pair<Point, Point>& crossPair) noexcept;
int getPoint(Circle c1, Circle c2, pair<Point, Point>& crossPair) noexcept;
int calPoint(vector<Line>& lineSet, set<Point>& pointSet);
int calPoint(vector<Line>& lineSet, vector<Segment>& segmentSet, set<Point>& pointSet);
int calPoint(vector<Line>& lineSet, vector<Ray>& raySet, set<Point>& pointSet);
int calPoint(vector<Line>& lineSet, vector<Circle>& circleSet, set<Point>& pointSet);
int calPoint(vector<Segment>& segmentSet, set<Point>& pointSet);
int calPoint(vector<Segment>& segmentSet, vector<Ray>& raySet, set<Point>& pointSet);
int calPoint(vector<Segment>& segmentSet, vector<Circle>& circleSet, set<Point>& pointSet);
int calPoint(vector<Ray>& raySet, set<Point>& pointSet);
int calPoint(vector<Ray>& raySet, vector<Circle>& circleSet, set<Point>& pointSet);
int calPoint(vector<Circle>& circleSet, set<Point>& pointSet);
int calPoint(vector<Line>& lineSet, vector<Segment>& segmentSet, vector<Ray>& raySet, vector<Circle>& circleSet, set<Point>& pointSet);
線形セグメントに線または線分の機能又はにおける重要な点は、放射線の範囲内か否かを判断します。
//将线段转化成对应的直线
//将横坐标较小的点作为p1,若两点横坐标相同则将纵坐标较小的点作为p1
Line segmentToLine(Segment s) {
Line l;
if ((s.p1.x < s.p2.x) || ((s.p1.x == s.p2.x) && (s.p1.y < s.p2.y))) {
l.p1 = s.p1;
l.p2 = s.p2;
} else {
l.p1 = s.p2;
l.p2 = s.p1;
}
return l;
}
//将射线转化成对应的直线
Line rayToLine(Ray r) {
Line l{ r.start, r.direction };
return l;
}
//判断一个点是否在一线段的坐标范围内
int pointIfOnSeg(Point p, Line l)
{
if (l.p1.x == l.p2.x) {
if ((p.y >= l.p1.y) && (p.y <= l.p2.y)) {
return ON;
} else {
return NOTON;
}
} else {
if ((p.x >= l.p1.x) && (p.x <= l.p2.x)) {
return ON;
} else {
return NOTON;
}
}
}
//判断一个点是否在一射线的坐标范围内
int pointIfOnRay(Point p, Line l)
{
if (l.p2.x < l.p1.x) {
//若射线指向负方向
if (p.x <= l.p1.x) {
return ON;
} else {
return NOTON;
}
} else if (l.p2.x == l.p1.x && l.p2.y < l.p1.y) {
//若射线指向正下方
if (p.y <= l.p1.y) {
return ON;
} else {
return NOTON;
}
} else if (l.p2.x == l.p1.x && l.p2.y > l.p1.y) {
//若射线指向正上方
if (p.y >= l.p1.y) {
return ON;
} else {
return NOTON;
}
} else {
//若射线指向正方向
if (p.x >= l.p1.x) {
return ON;
} else {
return NOTON;
}
}
}
計算モジュールインタフェース部6のパフォーマンスの改善
ランダムに生成されたテストセットを使用すると、データのより千以上の作品が含まれています。
もちろん、プログラムは上に挿入要素のセットでほとんどの時間を使用します。
また、正確な値に基づいても、多くの時間を取る書き換え等号の意味を決定しました
8.ユニットテストの表示計算モジュール
ショーの機能モジュールの設計部品上で定義され、計算モジュールは、LL、LR、LS、LC、分割され SS、SR、SC、RR、RC、CC 、いくつかの機能を限り、これらの計算にこれらの交点覆われているようgetPoint
な機能を、あなたその呼び出し、他のコンピューティング機能をカバーします。すべてカバーするためにcalPoint
機能をして、大規模なテスト・セットを作成し、すべての種類の完全なテストが含まれcalPoint
、より良いカバレッジを達成するための機能を。
//测试圆与圆交点的多种情况,除保证计算交点个数正确外,还要保证计算的交点坐标正确
TEST_METHOD(Circle_Circle_TwoCross)
{
Circle c1;
Circle c2;
c1.center.x = 0; c1.center.y = 0; c1.r = 2;
c2.center.x = 2; c2.center.y = 0; c2.r = 2;
Point realPoint1, realPoint2;
pair<Point, Point> testPair;
realPoint1.x = 1; realPoint1.y = 1.73205081;
realPoint2.x = 1; realPoint2.y = -1.73205081;
Assert::IsTrue(getPoint(c1, c2, testPair) == 2);
Assert::IsTrue(((realPoint1 == testPair.first) && (realPoint2 == testPair.second)) || ((realPoint2 == testPair.first) && (realPoint1 == testPair.second)));
}
TEST_METHOD(Circle_Circle_OneCross)
{
Circle c1;
Circle c2;
c1.center.x = 0; c1.center.y = 0; c1.r = 2;
c2.center.x = 4; c2.center.y = 0; c2.r = 2;
Point realPoint1, realPoint2;
pair<Point, Point> testPair;
realPoint1.x = 2; realPoint1.y = 0;
Assert::IsTrue(getPoint(c1, c2, testPair) == 1);
Assert::IsTrue(realPoint1 == testPair.first);
}
TEST_METHOD(Circle_Circle_NoCross)
{
Circle c1;
Circle c2;
c1.center.x = 0; c1.center.y = 0; c1.r = 2;
c2.center.x = 5; c2.center.y = 0; c2.r = 2;
Point realPoint1, realPoint2;
pair<Point, Point> testPair;
Assert::IsTrue(getPoint(c1, c2, testPair) == 0);
}
TEST_METHOD(TestAll)
{
vector<Line> lineSet;
vector<Segment> segmentSet;
vector<Ray> raySet;
vector<Circle> circleSet;
set<Point> pointSet;
Line l1, l2; Segment s1, s2, s3; Ray r1, r2, r3; Circle c1, c2;
l1.p1.x = 1; l1.p1.y = 2; l1.p2.x = 3; l1.p2.y = 3;
l2.p1.x = 4; l2.p1.y = 2; l2.p2.x = 2; l2.p2.y = -4;
lineSet.push_back(l1); lineSet.push_back(l2);
s1.p1.x = -5; s1.p1.y = 1; s1.p2.x = 5; s1.p2.y = -3;
s2.p1.x = 5; s2.p1.y = 3; s2.p2.x = 2; s2.p2.y = 2;
s3.p1.x = 6; s3.p1.y = -5; s3.p2.x = 6; s3.p2.y = 6;
segmentSet.push_back(s1); segmentSet.push_back(s2);
segmentSet.push_back(s3);
r1.start.x = 5; r1.start.y = 2; r1.direction.x = 3; r1.direction.y = 4;
r2.start.x = 2; r2.start.y = -4; r2.direction.x = -1; r2.direction.y = -1;
r3.start.x = -10; r3.start.y = 1; r3.direction.x = 10; r3.direction.y = 1;
raySet.push_back(r1); raySet.push_back(r2); raySet.push_back(r3);
c1.center.x = 2; c1.center.y = 3; c1.r = 4;
c2.center.x = 5; c2.center.y = 2; c2.r = 2;
circleSet.push_back(c1); circleSet.push_back(c2);
Assert::AreEqual(calPoint(lineSet, segmentSet, raySet, circleSet, pointSet), 31);
}
スクリーンショットカバレッジ計算モジュールのGeoCalculate.pp
カバレッジは90%に達しました。
9.計算モジュールセクションの例外処理命令。詳しくはブログのプレゼンテーションの設計目標の各例外。それぞれの異常がブログに投稿されたユニットテストのサンプルを選択し、シーンに対応するエラーを示す必要があります。
私たちは、次のカテゴリの例外をデザイン:
- 不正な入力フォーマット
- 幾何オブジェクトの欠如を入力します。
- あまりにもファイルの内容の末尾を入力します。
- 座標範囲は、上限を超え
- コマンドラインパラメータは、他の文字です
- 無数のための交差点の数
不正な入力フォーマット
このようなデータはない正しい幾何オブジェクト、スロー例外であるnは表示されませんファイルの先頭に、不正な文字、などの要件を満たしていない入力データに直面したとき illegalInputPattern
ユニットテストのサンプル:
幾何オブジェクトの欠如を入力します。
ファイルの最初の行は、Nから得られるが、入力データが少ないファイル後、Nより大きい場合、例外がスローされますnotEnoughInputElement
ユニットテストのサンプル:
あまりにもファイルの内容の末尾を入力します。
nと、n個あり、幾何学的オブジェクトファイル望ましくないコンテンツのデータの読み出しの後、例外がスローされますTooManyInputElements
ユニットテストのサンプル:
座標範囲は、上限を超え
各入力データに対して、ない場合、例外がスローされ、の範囲(-100000,100000)で決定されますoutRangeException
。小さな円はゼロまたは入力半径に等しいとき、これは例外をスローします。
ユニットテストのサンプル:
コマンドラインパラメータは、他の文字です
コマンドラインパラメータが正しくない場合は、例外がスローされますcommandException
。
「-d」のサンプル:(コマンドライン引数をテストするユニット)
交差点の数は無限の数です
二つの図は、交差点の多数の点がある場合は、例外がスローされますinfException
。
ユニットテストサンプル一致する二つの直線:()
詳細設計プロセス10インターフェース・モジュール。ブログの詳細ではどのようにモジュールをインターフェイスにするために設計されており、いくつかの必要なコードの記述が実装プロセスを説明書きされます。
モジュール開発インターフェースのQt Creatorを、二つのウィンドウのデザイン、メインインターフェイスダイアログは、他の描画インターフェースであるnew_window。
示すように、メインインターフェイス。
そして、4つの機能を紹介する一つ一つの実装しました:
-
ファイルを開きます
void Dialog::readFile()
機能使用
getOpenFileName
と、オープン、ファイルのファイルパスを取得する方法およびreadLine
ライン内容によってファイルの行を読み取るための方法、およびとsplit
空間に応じて文字列分割方法、対応する構造体に格納されています。最後に、使用してui->label->setText
readメソッドの内容は、インタフェース上に表示しました。「ファイルを開く」ボタンをクリックし、図のように、ファイルの結果を選択します。
-
グラフィックスを追加します
void Dialog::addone()
機能使用する
ui->text->toPlainText
と、テキストボックス内の文字列の取得方法split
、それぞれの構造に分割して格納する方法を。最後に、使用してui->label_2->setText
画面上に表示されるデータを追加する方法を。図効果に示す「追加」ボタンをクリックしてください:
-
削除グラフィックス
void Dialog::deleteone()
機能使用して
ui->text->toPlainText
、テキストボックスに文字列を取得する方法を、split
データに対応する要素を分割する方法が発見され、削除されます。最後に、使用ui->label_2->setText
方法を削除されたデータが画面に表示されています。示すように、「削除」ボタンの効果をクリックします。
-
グラフとの交点
void Dialog::open()
機能新しいウィンドウを開きnew_window、書き換え
paintEvent
方法、画像レンダリングを。描画方法:
- ライン:drawLine
- ラウンド:drawEllipse
- ポイント:drawPoint
示すような結果をレンダリングするグラフィックス:
ドッキングモジュールと計算モジュールインタフェース11。説明ドッキングUIモジュールの設計と詳細に二つのモジュール、およびブログで実装スクリーンショット機能。
我々は、交点計算を使用する必要があるcalPoint
直線セグメント、放射線、及び丸い点を表す5つのインターフェース構造の集合である方法を、。私のアイデアは、インターフェースモジュールは、同じ形で包装された構造直接法を算出することができる呼び出すことです。あなたは、このメソッドを直接呼び出すことができ、あなたのプロジェクトに関連するダイナミックリンクライブラリとヘッダファイルのリリースバージョンを追加します。
達成するための機能を表示します
示されるように、グラフィックファイルから3を追加し、手動でパターン(線)を追加します。
示すように、ボタンの結果「グラフィックスとの交差点を描く」をクリックしてください:
示されるように、グラフィックファイルから4を追加し、手動でパターン(線)を削除します。
示すように、ボタンの結果「グラフィックスとの交差点を描く」をクリックしてください: