C++ Hình Họa Không Gian: C++ Arc

Hi, chào mừng các bạn đến với chủ đề c++ hình họa không gian.

Trong bài trước, các bạn đã biết cách xây dựng lớp đối tượng Elipse.

Bài hôm nay chúng ta sẽ cùng nghiên cứu về một đối tượng hình học Arc.

Arc là đối tượng phổ biến trong hình học, và được sử dụng nhiều trong mô phỏng đồ họa.

1. Lý thuyết cơ bản.

a. Tính chất của Arc.

arc là một phần của cung tròn, do đó nó cũng cần

– Cần một điểm tâm.

– Bán kính đường tròn chứa nó.

– Góc bắt đầu

– Góc kết thúc.

– Điểm bắt đầu, điểm kết thúc.

 

b. Các hàm xử lý.

– Hàm khởi tạo/hàm hủy cơ bản

– Hàm get/set điểm tâm của Arc

– Hàm get/set tham số r của Arc

– Hàm set/get góc start, góc end

– Hàm set/get 2 điểm bắt đầu kết thúc

– Hàm check 1 điểm nằm trên arc hay không ?

Arc là một đối tượng khá phức tạp, trong bài viết này, tạm thời tôi chia sẻ mã code xây dựng arc từ 3 điểm bất kỳ.

 

2. Code sample.

File header.

#ifndef TARC_H_
#define TARC_H_

#include <vector>
#include "TPoint2D.h"
#include "TLine.h"

#define T_PI       3.14159265358979323846   // pi

class TArc
{
public:
    TArc();
    TArc(const TPoint2D& p1, const TPoint2D& p2, const TPoint2D& p3);
    ~TArc();

    enum TypeArc
    {
        ARC_NONE = -1,
        ARC_CLOCKWISE = 0,
        ARC_ANTI_CLOCKWISE = 1,
    };

    float GetRadius() const { return m_rad; }
    TPoint2D GetCenterPoint() { return m_ptCenter; }

    //float GetArea();
    float GetPerimeter();

    //int CheckRelPoint(const TPoint3D& p);
    void FindCircle(TPoint2D& centerPt, float& rad);
    void MakeData();
    void SetPoint(const TPoint2D& p1, const TPoint2D& p2, const TPoint2D& p3)
    {
        m_pt[0] = p1;
        m_pt[1] = p2;
        m_pt[2] = p3;
    }

    TPoint2D* GetPoint()
    {
        return &m_pt[0];
    }

    std::vector<TPoint2D> GetPointSegment() 
    {
        return m_ptSegment;
    }
private:
    std::vector<TPoint2D> m_ptSegment;
    TPoint2D m_pt[3];
    int m_SegDiv;
    int m_type;
    float m_rad;
    TPoint2D m_ptCenter;
    float m_total_angle;
};

#endif

File Cpp

#include "TArc.h"


TArc::TArc()
{
    m_type = ARC_ANTI_CLOCKWISE;
    m_SegDiv = 100;
}

TArc::TArc(const TPoint2D& p1, const TPoint2D& p2, const TPoint2D& p3)
{
    //m_center = p;
    //m_radius = rad;
    m_pt[0] = p1;
    m_pt[1] = p2;
    m_pt[2] = p3;

    m_type = ARC_ANTI_CLOCKWISE;
    m_SegDiv = 100;
}

TArc::~TArc()
{

}

void TArc::FindCircle(TPoint2D& centerPt, float& rad)
{
    float x1 = m_pt[0].x_;
    float y1 = m_pt[0].y_;

    float x2 = m_pt[1].x_;
    float y2 = m_pt[1].y_;

    float x3 = m_pt[2].x_;
    float y3 = m_pt[2].y_;

    float x12 = x1 - x2;
    float x13 = x1 - x3;

    float y12 = y1 - y2;
    float y13 = y1 - y3;

    float y31 = y3 - y1;
    float y21 = y2 - y1;

    float x31 = x3 - x1;
    float x21 = x2 - x1;

    // x1^2 - x3^2
    float sx13 = pow(x1, 2) - pow(x3, 2);

    // y1^2 - y3^2
    float sy13 = pow(y1, 2) - pow(y3, 2);

    float sx21 = pow(x2, 2) - pow(x1, 2);
    float sy21 = pow(y2, 2) - pow(y1, 2);

    float data1 = ((sx13) * (x12)+(sy13) * (x12)+(sx21) * (x13)+(sy21) * (x13));
    float data2 = (2 * ((y31) * (x12)-(y21) * (x13)));
    float f =  data1 / data2;

    data1 = ((sx13) * (y12)+(sy13) * (y12)+(sx21) * (y13)+(sy21) * (y13));
    data2 = (2 * ((x31) * (y12)-(x21) * (y13)));
    float g =  data1/data2 ;

    float c = -pow(x1, 2) - pow(y1, 2) - 2 * g * x1 - 2 * f * y1;

    // x^2 + y^2 + 2*g*x + 2*f*y + c = 0
    // r^2 = h^2 + k^2 - c
    centerPt.x_ = -g;
    centerPt.y_ = -f;
    float sqr_of_r = centerPt.x_ * centerPt.x_ + centerPt.y_ * centerPt.y_ - c;
    rad = sqrt(sqr_of_r);
}

void TArc::MakeData()
{
    TPoint2D centerPt;
    float rad = 0.0;

    FindCircle(centerPt, rad);
    m_rad = rad;
    m_ptCenter = centerPt;

    TVector2D v1 = m_pt[1] - m_pt[0];
    TVector2D v2 = m_pt[2] - m_pt[1];
    TVector2D vSum = v1 + v2;
    vSum.Unit();

    float angle = vSum.AngleTo(TVector2D(1.0, 0.0));
    if (fabs(angle) < T_PI / 2.0)
    {
        m_type = ARC_CLOCKWISE;
    }
    else
    {
        m_type = ARC_ANTI_CLOCKWISE;
    }

    TVector2D vr1 = m_pt[0] - centerPt;
    TVector2D vr2 = m_pt[2] - centerPt;

    m_total_angle = vr1.AngleTo(vr2);

    if (m_type == ARC_ANTI_CLOCKWISE)
    {
        if (m_total_angle < 0)
        {
            m_total_angle = m_total_angle + 2*T_PI;
        }
    }
    else
    {
        if (m_total_angle > 0)
        {
            m_total_angle = m_total_angle - 2 * T_PI;
        }
    }

    float dAngle = m_total_angle / m_SegDiv;

    m_ptSegment.push_back(m_pt[0]);
    for (int i = 0; i < m_SegDiv; i++)
    {
        TVector2D vRot = vr1.Rotate((i+1)*dAngle);
        TPoint2D pt = centerPt.GetPointDis(vRot, rad);
        m_ptSegment.push_back(pt);
    }
}


float TArc::GetPerimeter()
{
    float c = 2 * m_rad*m_total_angle;
    return c;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.