Page 1 of 1

Bezier curve control

Posted: Wed Apr 25, 2018 12:17 pm
by NoeMurr
Hi all,
I'm writing an application that needs to print a Bezier curve on a panel. That curves needs to be clickable, movable, etc. so I need it to be a "control", but wxControl has a rectangular shape and my curve, of course, cannot be wrapped in a rectangle.

Is there a way to have a custom control that does not have rectangular shape?

Re: Bezier curve control

Posted: Wed Apr 25, 2018 1:41 pm
by New Pagodi
Here's one approach for drawing a dragable curve on a panel. The idea is to keep track of the points in a vector and handle the mouse events for adding or dragging points.

Code: Select all

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

class myFrame : public wxFrame
{
    public:
        myFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo"
                , wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize
                , int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
    private:
        void OnLeftDown( wxMouseEvent& event );
        void OnLeftUp( wxMouseEvent& event );
        void OnMotion( wxMouseEvent& event );
        void OnPaint( wxPaintEvent& event );

        std::vector<wxPoint> m_points;
        std::vector<wxPoint>::iterator m_selection;
        wxPanel* m_panel;
};


myFrame::myFrame( wxWindow* parent, int id, wxString title, wxPoint pos
                 , wxSize size, int style )
        :wxFrame( parent, id, title, pos, size, style )
{
    m_selection=m_points.end();
    m_panel = new wxPanel(this);

    m_panel->Bind( wxEVT_LEFT_DOWN, &myFrame::OnLeftDown, this );
    m_panel->Bind( wxEVT_LEFT_UP, &myFrame::OnLeftUp, this );
    m_panel->Bind( wxEVT_MOTION, &myFrame::OnMotion, this );
    m_panel->Bind( wxEVT_PAINT, &myFrame::OnPaint, this );
}

void myFrame::OnLeftDown( wxMouseEvent& event )
{
    wxPoint p = event.GetPosition();

    for (std::vector<wxPoint>::iterator it=m_points.begin();it!=m_points.end();++it)
    {
        if ( std::abs(it->x-p.x) + std::abs(it->y-p.y) < 8 )
        {
            m_selection=it;
            m_selection->x=p.x;
            m_selection->y=p.y;
        }
    }

    if (m_selection==m_points.end())
    {
        m_points.push_back(p);
        m_selection = m_points.end();
        --m_selection;
    }
    m_panel->Refresh();
}

void myFrame::OnLeftUp( wxMouseEvent& event )
{
    m_selection=m_points.end();
    m_panel->Refresh();
}

void myFrame::OnMotion( wxMouseEvent& event )
{
    if (event.LeftIsDown() && m_selection!=m_points.end())
    {
        wxPoint p = event.GetPosition();
        m_selection->x=p.x;
        m_selection->y=p.y;
        m_panel->Refresh();
    }
}

void myFrame::OnPaint( wxPaintEvent& event )
{
    wxPaintDC dc(m_panel);
    dc.Clear();

    dc.SetPen(*wxBLACK_PEN);
    dc.SetBrush(*wxWHITE_BRUSH);

    if (m_points.size()>2)
    {
        dc.DrawSpline(m_points.size(),&(m_points[0]));
    }

    for (std::vector<wxPoint>::iterator it=m_points.begin();it!=m_points.end();++it)
    {
        dc.DrawCircle(*it, 4);
    }

    if ( m_selection!=m_points.end() )
    {
        dc.SetPen(*wxRED_PEN);
        dc.SetBrush(*wxRED_BRUSH);
        dc.DrawCircle(*m_selection, 4);
    }
}

class myApp : public wxApp
{
    public:
        virtual bool OnInit()
        {
            myFrame* frame = new myFrame(NULL);
            frame->Show();
            return true;
        }
};

wxIMPLEMENT_APP(myApp);
bez.png
bez.png (2.31 KiB) Viewed 15446 times
This obviously isn't complete. I know the above code will have problems when the mouse leaves the window. To fix this, either the mouse should be captured in the left down event or an event handler for the wxEVT_LEAVE_WINDOW event should be added. There may be other problems as well.

Re: Bezier curve control

Posted: Wed Apr 25, 2018 3:37 pm
by ONEEYEMAN
Hi,
The best way is to use a pre-written library for such stuff.

For wxWidgets, there are wxArt2D, wxShapeFramework and wxWorkspaceView (ref. https://wiki.wxwidgets.org/WxFAQ#How_ca ... d_nodes.3F).

Thank you.