1

ここに画像の説明を入力これは簡単な質問ですが、間違った方法で考えている可能性があり、正しい方法を見つけることができませんでした。

m_StartPoint1 から始まり m_EndPoint1 で終わる行、たとえば行 1 があるとします。m_EndPoint1 から始まり、線 1 と一定の角度のアルファを持つ別の線、たとえば線 2 を描きたいと思います。基本的に私の目標は、矢印を描くことです。

次のコードを使用して、ライン 2 の x、y 座標を計算しています。

 const float ARROW_ANGLE=-PI/8.0;
 wxPoint p;
 p.x=m_EndPoint.x+ARROW_LENGTH*sin(ARROW_ANGLE);
 p.y=m_EndPoint.y+ARROW_LENGTH*cos(ARROW_ANGLE);
 m_ArrowHead1=new CLine(m_EndPoint,p,color,PenWidth); //Draws a line from m_EndPoint to p

この計算は、ライン 1 の角度が 90 (度) 未満の場合にうまく機能します。ただし、ライン 1 の角度が変わると、矢印が正しく表示されません。基本的には、ユーザーが自由に線 1 を描くことができ、線 1 の角度に関係なく矢印線が正しく表示される必要があります。

ライン 1 をベクトルとして表現し、次のコードでその角度を取得しました。

class CVector2D
{
wxPoint m_StartPoint, m_EndPoint;
public:
CVector2D():m_StartPoint(),m_EndPoint()  {}
CVector2D(wxPoint p1, wxPoint p2):m_StartPoint(p1),m_EndPoint(p2)  {}

float GetSlope(void)
{
    return float(m_EndPoint.y-m_StartPoint.y)/float(m_EndPoint.x-m_StartPoint.x);
}

float GetSlopeAngleInRadians()
{
       /*Will return the angle of the vector in radians
   * The angle is the counterclockwise rotation therefore it is negative
    */
    float slope=GetSlope();
    float InRadians=atan2(float(m_EndPoint.y-m_StartPoint.y),float(m_EndPoint.x-m_StartPoint.x));
    if(InRadians<=0) return InRadians;
    return -(2*PI-InRadians);
}
 };

そして、次のコードで計算しようとしました:

CVector2D vector(m_StartPoint,m_EndPoint);
float vector_angle=vector.GetSlopeAngleInRadians();
float total_angle=vector_angle+ARROW_ANGLE;
wxPoint p;
p.x=m_EndPoint.x+ARROW_LENGTH*cos(total_angle);
p.y=m_EndPoint.y+ARROW_LENGTH*sin(total_angle);
m_ArrowHead1=new CLine(m_EndPoint,p,color,PenWidth);

ただし、このコードも機能しませんでした。どんなアイデアでも大歓迎です。

4

4 に答える 4

0

ここでの難しさは、おそらくプログラミングよりも数学に関するものです。ただし、特異点の処理には注意が必要です。

次の例で、90 度でゼロ除算を防ぐにはどうすればよいですか。

float GetSlope(void)
{
    return float(m_EndPoint.y-m_StartPoint.y)/float(m_EndPoint.x-m_StartPoint.x);
}

内積ベースの数学をお勧めします。次を参照してください: 2 つのベクトル間の角度が外部か内部かを調べるには?

PS float の代わりに double を使用しないのはなぜですか?

于 2013-09-22T11:04:59.163 に答える
0

ARROW_LENGTHまず、からm_EndPointまでの長さの線を引くには、pこれを使用する必要があります (数式にエラーがあると思います)。

 wxPoint p;
 p.x=m_EndPoint.x+ARROW_LENGTH*cos(ARROW_ANGLE);
 p.y=m_EndPoint.y+ARROW_LENGTH*sin(ARROW_ANGLE);
 m_ArrowHead1=new CLine(m_EndPoint,p,color,PenWidth);

次に、相対角度で線を描くには、角度を追加します

new_angle = ARROW_ANGLE + ANGLE_BETWEEN_LINES

しかし:

三角関数の周期性を考慮に入れるように注意してください。あなたが言ったように勾配が得られた場合:

float GetSlope(void)
{
    return float(m_EndPoint.y-m_StartPoint.y)/float(m_EndPoint.x-m_StartPoint.x);
}

これは関数でtan(angle)あり、注入ではないことを覚えておいてください。したがって、角度が第 1 象限にあるか第 3 象限にあるかについての情報が失われます。説明されている式を使用して線を引くには、これから (第 1 または第 3 四半期の引数) から角度の正しい値を取得する必要があります。使用できます。tangent

std::atan2()

2 つのパラメーターを使用して逆正接を計算します。y/x のアーク タンジェントの主値をラジアンで返します。符号があいまいであるにもかかわらず、この関数は角度がどの象限に収まるかを確実に判断することに注意してください。小数引数を取ります。値を計算するために、関数は象限を決定するために両方の引数の符号を考慮します。

そして、この値を使用して を計算できますnew_angle。したがって、次のようになります。

float GetSlope(void)
{
    return std::atan2(m_EndPoint.y-m_StartPoint.y, m_EndPoint.x-m_StartPoint.x);
}

wxPoint p;
 p.x=m_EndPoint.x+ARROW_LENGTH*cos(GetSlope()+ANGLE_BETWEEN_LINES);
 p.y=m_EndPoint.y+ARROW_LENGTH*sin(GetSlope()+ANGLE_BETWEEN_LINES);
 m_ArrowHead1=new CLine(m_EndPoint,p,color,PenWidth);

atan2PI/2 と 3/2PI のケースを個別に処理する必要がないためです。

于 2013-09-22T11:40:49.433 に答える
0

次のコードを使用して質問を解決しました。

CVector2D vector(m_StartPoint,m_EndPoint);
float vector_angle=vector.GetSlopeAngleInRadians();
float total_angle=vector_angle+ARROW_ANGLE; //ARROW_ANGLE=-PI/8, so is negative too

wxPoint p;
p.x=m_EndPoint.x-ARROW_LENGTH*cos(total_angle);
p.y=m_EndPoint.y-ARROW_LENGTH*sin(total_angle);
m_ArrowHead1=new CLine(m_EndPoint,p,color,PenWidth);

total_angle=vector_angle-ARROW_ANGLE;
p.x=m_EndPoint.x-ARROW_LENGTH*cos(total_angle);
p.y=m_EndPoint.y-ARROW_LENGTH*sin(total_angle);
m_ArrowHead2=new CLine(m_EndPoint,p,color,PenWidth);

どのように描いても完璧な矢印を描くようになりました。皆さんのアイデアに感謝します。

于 2013-09-25T10:44:17.553 に答える