]> git.saurik.com Git - wxWidgets.git/commitdiff
Adding new wxCanvas
authorRobert Roebling <robert@roebling.de>
Fri, 24 Nov 2000 12:34:35 +0000 (12:34 +0000)
committerRobert Roebling <robert@roebling.de>
Fri, 24 Nov 2000 12:34:35 +0000 (12:34 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@8790 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

contrib/src/canvas/Makefile.in
contrib/src/canvas/bbox.cpp [new file with mode: 0644]
contrib/src/canvas/canvas.cpp
contrib/src/canvas/liner.cpp [new file with mode: 0644]
contrib/src/canvas/polygon.cpp [new file with mode: 0644]

index 3cf2445e2a8451de61ecbded45a67537f342ce46..7c32c4f6fc55bb83a354a1b8cf77fa6bc1f1c28d 100644 (file)
@@ -13,9 +13,9 @@ LIBVERSION_AGE=0
 HEADER_PATH=$(top_srcdir)/contrib/include/wx
 HEADER_SUBDIR=canvas
 
-HEADERS=canvas.h
+HEADERS=canvas.h bbox.h liner.h polygon.h
 
-OBJECTS=canvas.o
+OBJECTS=canvas.o bbox.o liner.o polygon.o
 
 APPEXTRADEFS=-I$(top_srcdir)/contrib/include
 
diff --git a/contrib/src/canvas/bbox.cpp b/contrib/src/canvas/bbox.cpp
new file mode 100644 (file)
index 0000000..bc90fee
--- /dev/null
@@ -0,0 +1,369 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        bbox.cpp
+// Author:      Klaas Holwerda
+// Created:     XX/XX/XX
+// Copyright:   2000 (c) Klaas Holwerda
+// Licence:     wxWindows Licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+    #pragma implementation "bbox.cpp"
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#include "bbox.h"
+
+wxBoundingBox::wxBoundingBox()
+{
+    m_minx = m_miny = m_maxx =  m_maxy = 0.0;
+    m_validbbox = FALSE;
+}
+
+
+wxBoundingBox::wxBoundingBox(wxBoundingBox &other)
+{
+    m_minx = other.m_minx;
+    m_miny = other.m_miny;
+    m_maxx = other.m_maxx;
+    m_maxy = other.m_maxy;
+    m_validbbox= other.m_validbbox;
+}
+
+
+wxBoundingBox::wxBoundingBox(const wxPoint2DDouble& a)
+{
+    m_minx = a.m_x;
+    m_maxx = a.m_x;
+    m_miny = a.m_y;
+    m_maxy = a.m_y;
+    m_validbbox = TRUE;
+}
+
+wxBoundingBox::wxBoundingBox(double xmin, double ymin, double xmax, double ymax)
+{
+    m_minx = xmin;
+    m_miny = ymin;
+    m_maxx = xmax;
+    m_maxy = ymax;
+    m_validbbox = TRUE;
+}
+
+// This function checks if two bboxes intersect
+bool wxBoundingBox::And(wxBoundingBox *_bbox, double Marge)
+{
+    assert (m_validbbox == TRUE);
+    assert (_bbox->GetValid());
+    m_minx = wxMax(m_minx, _bbox->m_minx);
+    m_maxx = wxMin(m_maxx, _bbox->m_maxx);
+    m_miny = wxMax(m_miny, _bbox->m_miny);
+    m_maxy = wxMin(m_maxy, _bbox->m_maxy);
+    return (bool)
+             (
+             ((m_minx - Marge) < (m_maxx + Marge)) &&
+             ((m_miny - Marge) < (m_maxy + Marge))
+             );
+}
+
+// Shrink the boundingbox with the given marge
+void wxBoundingBox::Shrink(const double Marge)
+{
+    assert (m_validbbox == TRUE);
+
+    m_minx += Marge;
+    m_maxx -= Marge;
+    m_miny += Marge;
+    m_maxy -= Marge;
+}
+
+
+// Expand the boundingbox with another boundingbox
+void wxBoundingBox::Expand(const wxBoundingBox &other)
+{
+    if (!m_validbbox)
+    {
+        *this=other;
+    }
+    else
+    {
+        m_minx = wxMin(m_minx, other.m_minx);
+        m_maxx = wxMax(m_maxx, other.m_maxx);
+        m_miny = wxMin(m_miny, other.m_miny);
+        m_maxy = wxMax(m_maxy, other.m_maxy);
+    }
+}
+
+
+// Expand the boundingbox with a point
+void wxBoundingBox::Expand(const wxPoint2DDouble& a_point)
+{
+    if (!m_validbbox)
+    {
+        m_minx = m_maxx = a_point.m_x;
+        m_miny = m_maxy = a_point.m_y;
+        m_validbbox=TRUE;
+    }
+    else
+    {
+        m_minx = wxMin(m_minx, a_point.m_x);
+        m_maxx = wxMax(m_maxx, a_point.m_x);
+        m_miny = wxMin(m_miny, a_point.m_y);
+        m_maxy = wxMax(m_maxy, a_point.m_y);
+    }
+}
+
+// Expand the boundingbox with a point
+void wxBoundingBox::Expand(double x,double y)
+{
+    if (!m_validbbox)
+    {
+        m_minx = m_maxx = x;
+        m_miny = m_maxy = y;
+        m_validbbox=TRUE;
+    }
+    else
+    {
+        m_minx = wxMin(m_minx, x);
+        m_maxx = wxMax(m_maxx, x);
+        m_miny = wxMin(m_miny, y);
+        m_maxy = wxMax(m_maxy, y);
+    }
+}
+
+
+// Expand the boundingbox with two points
+void wxBoundingBox::Expand(const wxPoint2DDouble& a, const wxPoint2DDouble& b)
+{
+    Expand(a);
+    Expand(b);
+}
+
+// Enlarge the boundingbox with the given marge
+void wxBoundingBox::EnLarge(const double marge)
+{
+    if (!m_validbbox)
+    {
+        m_minx = m_maxx = marge;
+        m_miny = m_maxy = marge;
+        m_validbbox=TRUE;
+    }
+    else
+    {
+        m_minx -= marge;
+        m_maxx += marge;
+        m_miny -= marge;
+        m_maxy += marge;
+    }
+}
+
+// Calculates if two boundingboxes intersect. If so, the function returns _ON.
+// If they do not intersect, two scenario's are possible:
+// other is outside this -> return _OUT
+// other is inside this -> return _IN
+OVERLAP wxBoundingBox::Intersect(wxBoundingBox &other, double Marge)
+{
+    assert (m_validbbox == TRUE);
+
+    // other boundingbox must exist
+    assert (&other);
+
+    if (((m_minx - Marge) > (other.m_maxx + Marge)) ||
+         ((m_maxx + Marge) < (other.m_minx - Marge)) ||
+         ((m_maxy + Marge) < (other.m_miny - Marge)) ||
+         ((m_miny - Marge) > (other.m_maxy + Marge)))
+        return _OUT;
+
+    // Check if other.bbox is inside this bbox
+    if ((m_minx <= other.m_minx) &&
+         (m_maxx >= other.m_maxx) &&
+         (m_maxy >= other.m_maxy) &&
+         (m_miny <= other.m_miny))
+        return _IN;
+
+    // Boundingboxes intersect
+    return _ON;
+}
+
+
+// Checks if a line intersects the boundingbox
+bool wxBoundingBox::LineIntersect(const wxPoint2DDouble& begin, const wxPoint2DDouble& end )
+{
+    assert (m_validbbox == TRUE);
+
+    return (bool)
+              !(((begin.m_y > m_maxy) && (end.m_y > m_maxy)) ||
+                ((begin.m_y < m_miny) && (end.m_y < m_miny)) ||
+                ((begin.m_x > m_maxx) && (end.m_x > m_maxx)) ||
+                ((begin.m_x < m_minx) && (end.m_x < m_minx)));
+}
+
+
+// Is the given point in the boundingbox ??
+bool wxBoundingBox::PointInBox(double x, double y, double Marge)
+{
+    assert (m_validbbox == TRUE);
+
+    if (  x >= (m_minx - Marge) && x <= (m_maxx + Marge) &&
+            y >= (m_miny - Marge) && y <= (m_maxy + Marge) )
+            return TRUE;
+    return FALSE;
+}
+
+
+//
+// Is the given point in the boundingbox ??
+//
+bool wxBoundingBox::PointInBox(const wxPoint2DDouble& a, double Marge)
+{
+    assert (m_validbbox == TRUE);
+
+    return PointInBox(a.m_x, a.m_y, Marge);
+}
+
+
+wxPoint2DDouble wxBoundingBox::GetMin()
+{
+    assert (m_validbbox == TRUE);
+
+    return wxPoint2DDouble(m_minx, m_miny);
+}
+
+
+wxPoint2DDouble wxBoundingBox::GetMax()
+{
+    assert (m_validbbox == TRUE);
+
+    return wxPoint2DDouble(m_maxx, m_maxy);
+}
+
+bool wxBoundingBox::GetValid() const
+{
+    return m_validbbox;
+}
+
+void wxBoundingBox::SetMin(double px, double py)
+{
+    m_minx = px;
+    m_miny = py;
+    if (!m_validbbox)
+    {
+        m_maxx = px;
+        m_maxy = py;
+        m_validbbox = TRUE;
+    }
+}
+
+void wxBoundingBox::SetMax(double px, double py)
+{
+    m_maxx = px;
+    m_maxy = py;
+    if (!m_validbbox)
+    {
+        m_minx = px;
+        m_miny = py;
+        m_validbbox = TRUE;
+    }
+}
+
+void wxBoundingBox::SetValid(bool value)
+{
+    m_validbbox = value;
+}
+
+// adds an offset to the boundingbox
+// usage : a_boundingbox.Translate(a_point);
+void wxBoundingBox::Translate(wxPoint2DDouble& offset)
+{
+    assert (m_validbbox == TRUE);
+
+    m_minx += offset.m_x;
+    m_maxx += offset.m_x;
+    m_miny += offset.m_y;
+    m_maxy += offset.m_y;
+}
+
+
+// clears the bounding box settings
+void wxBoundingBox::Reset()
+{
+    m_minx = 0.0;
+    m_maxx = 0.0;
+    m_miny = 0.0;
+    m_maxy = 0.0;
+    m_validbbox = FALSE;
+}
+
+
+void wxBoundingBox::SetBoundingBox(const wxPoint2DDouble& a_point)
+{
+    m_minx = a_point.m_x;
+    m_maxx = a_point.m_x;
+    m_miny = a_point.m_y;
+    m_maxy = a_point.m_y;
+}
+
+
+// Expands the boundingbox with the given point
+// usage : a_boundingbox = a_boundingbox + pointer_to_an_offset;
+wxBoundingBox& wxBoundingBox::operator+(wxBoundingBox &other)
+{
+    assert (m_validbbox == TRUE);
+    assert (other.GetValid());
+
+    Expand(other);
+    return *this;
+}
+
+
+// makes a boundingbox same as the other
+wxBoundingBox& wxBoundingBox::operator=( const wxBoundingBox &other)
+{
+    assert (other.GetValid());
+
+    m_minx = other.m_minx;
+    m_maxx = other.m_maxx;
+    m_miny = other.m_miny;
+    m_maxy = other.m_maxy;
+    m_validbbox = other.m_validbbox;
+    return *this;
+}
+
+void wxBoundingBox::MapBbox( const wxTransformMatrix& matrix)
+{
+    assert (m_validbbox == TRUE);
+
+    double x1,y1,x2,y2,x3,y3,x4,y4;
+
+    matrix.TransformPoint( m_minx, m_miny, x1, y1 );
+    matrix.TransformPoint( m_minx, m_maxy, x2, y2 );
+    matrix.TransformPoint( m_maxx, m_maxy, x3, y3 );
+    matrix.TransformPoint( m_maxx, m_miny, x4, y4 );
+
+    double xmin = wxMin(x1,x2);
+    xmin = wxMin(xmin,x3);
+    xmin = wxMin(xmin,x4);
+
+    double xmax = wxMax( x1, x2);
+    xmax = wxMax(xmax,x3);
+    xmax = wxMax(xmax,x4);
+
+    double ymin = wxMin(y1, y2);
+    ymin = wxMin(ymin,y3);
+    ymin = wxMin(ymin,y4);
+
+    double ymax = wxMax(y1,y2);
+    ymax = wxMax(ymax,y3);
+    ymax = wxMax(ymax,y4);
+
+    // Use these min and max values to set the new boundingbox
+    m_minx = xmin;
+    m_miny = ymin;
+    m_maxx = xmax;
+    m_maxy = ymax;
+}
+
index 1be997526aeec5e68ea0b5e059ec75b7cbc43444..f0b3983b5a2a9099b486a9a85072030d56473327 100644 (file)
@@ -17,7 +17,9 @@
     #pragma hdrstop
 #endif
 
-#include "wx/canvas/canvas.h"
+#include "canvas.h"
+#include "polygon.h"
+#include "liner.h"
 
 #ifdef __WXGTK__
     #include <gtk/gtk.h>
 #endif
 
 #ifndef wxUSE_FREETYPE
-    #define wxUSE_FREETYPE 1
+    #define wxUSE_FREETYPE 0
 #endif
 
 #if wxUSE_FREETYPE
     #include <freetype/freetype.h>
 #endif
 
+//#define CANVASDEBUG
+
 //----------------------------------------------------------------------------
 // globals
 //----------------------------------------------------------------------------
 
+const double pi = 3.1415926535;
+
 #if wxUSE_FREETYPE
 FT_Library g_freetypeLibrary;
 #endif
@@ -44,81 +50,357 @@ FT_Library g_freetypeLibrary;
 //----------------------------------------------------------------------------
 // wxCanvasObject
 //----------------------------------------------------------------------------
-
 wxCanvasObject::wxCanvasObject()
 {
-    m_owner = NULL;
-    m_area.x = -1;
-    m_area.y = -1;
-    m_area.width = -1;
-    m_area.height = -1;
+    // the default event handler is just this object
+    m_eventHandler=this;
+    m_admin = NULL;
     m_isControl = FALSE;
     m_isVector = FALSE;
     m_isImage = FALSE;
+    m_visible  = TRUE;
+    m_dragmode = DRAG_ONTOP;
+//  handy when debugging
+//  m_dragmode = DRAG_RECTANGLE;
+    m_dragable = TRUE;
+}
+
+bool wxCanvasObject::ProcessCanvasObjectEvent(wxEvent& event)
+{
+    return m_eventHandler->ProcessEvent(event);
+}
+
+void wxCanvasObject::PushEventHandler(wxEvtHandler *handler)
+{
+    handler->SetNextHandler(GetEventHandler());
+    m_eventHandler=handler;
+}
+
+wxEvtHandler *wxCanvasObject::PopEventHandler(bool deleteHandler)
+{
+    wxEvtHandler *handlerA = m_eventHandler;
+    if ( handlerA )
+    {
+        wxEvtHandler *handlerB = handlerA->GetNextHandler();
+        handlerA->SetNextHandler((wxEvtHandler *)NULL);
+        m_eventHandler=handlerB;
+        if ( deleteHandler )
+        {
+            delete handlerA;
+            handlerA = (wxEvtHandler *)NULL;
+        }
+    }
+
+    return handlerA;
+}
+
+void wxCanvasObject::AppendEventHandler(wxEvtHandler *handler)
+{
+    GetEventHandler()->SetNextHandler(handler);
+}
+
+wxEvtHandler *wxCanvasObject::RemoveLastEventHandler(bool deleteHandler)
+{
+    //always the first in the row
+    wxEvtHandler *handlerA = m_eventHandler;
+    wxEvtHandler *handlerB=handlerA;
+    //goto the end
+    while ( handlerA->GetNextHandler() )
+    {
+        handlerB = handlerA;
+        handlerA = handlerA->GetNextHandler();
+    }
+
+    handlerB->SetNextHandler((wxEvtHandler *)NULL);
+    if ( deleteHandler )
+    {
+        delete handlerA;
+    }
+
+    return GetEventHandler();
+}
+
+wxRect wxCanvasObject::GetAbsoluteArea(const wxTransformMatrix& cworld)
+{
+
+    wxBoundingBox tmp=m_bbox;
+    tmp.MapBbox(cworld);
+
+
+    int x1 = m_admin->LogicalToDeviceX( tmp.GetMinX() );
+    int y1 = m_admin->LogicalToDeviceY( tmp.GetMinY() );
+    int x2 = m_admin->LogicalToDeviceX( tmp.GetMaxX() );
+    int y2 = m_admin->LogicalToDeviceY( tmp.GetMaxY() );
+
+    if (x1 > x2)
+    {
+        int tmp = x1;
+        x1 = x2;
+        x2 = tmp;
+    }
+    if (y1 > y2)
+    {
+        int tmp = y1;
+        y1 = y2;
+        y2 = tmp;
+    }
+
+    wxRect tmparea;
+    tmparea.x = x1;
+    tmparea.y = y1;
+    tmparea.width = x2-x1;
+    tmparea.height = y2-y1;
+
+    return tmparea;
+}
+
+void wxCanvasObject::MoveAbsolute( double x, double y )
+{
+    //save old position of boundingbox
+    double oldx = GetXMin();
+    double oldy = GetYMin();
+    double w = m_bbox.GetWidth();
+    double h = m_bbox.GetHeight();
+
+    SetPosXY(x,y);
+
+    double newx=GetXMin();
+    double newy=GetYMin();
+
+    double leftu,rightu,bottomu,topu ;
+    leftu   = wxMin (oldx, newx ) ;
+    rightu  = wxMax (oldx + w, newx + w) ;
+    topu    = wxMin (oldy, newy) ;
+    bottomu = wxMax (oldy + h, newy + h) ;
+
+    if ( rightu - leftu < 2*w && bottomu - topu < 2*h )
+    {
+        m_admin->Update( this,leftu, topu, rightu - leftu, bottomu - topu);
+    }
+    else
+    {
+        m_admin->Update( this, oldx, oldy, w, h );
+        m_admin->Update( this, newx, newy, w, h );
+    }
 }
 
-void wxCanvasObject::SetArea( int x, int y, int width, int height )
+void wxCanvasObject::MoveRelative( double x, double y )
 {
-    m_area.x = x;
-    m_area.y = y;
-    m_area.width = width;
-    m_area.height = height;
+    //save old position of boundingbox
+    double oldx = GetXMin();
+    double oldy = GetYMin();
+    double w = m_bbox.GetWidth();
+    double h = m_bbox.GetHeight();
+
+    TransLate(x,y);
+
+    double newx=GetXMin();
+    double newy=GetYMin();
+
+    double leftu,rightu,bottomu,topu ;
+    leftu   = wxMin (oldx, newx ) ;
+    rightu  = wxMax (oldx + w, newx + w) ;
+    topu    = wxMin (oldy, newy) ;
+    bottomu = wxMax (oldy + h, newy + h) ;
+
+    if ( rightu - leftu < 2*w && bottomu - topu < 2*h )
+    {
+        m_admin->Update( this,leftu, topu, rightu - leftu, bottomu - topu);
+    }
+    else
+    {
+        m_admin->Update( this, oldx, oldy, w, h );
+        m_admin->Update( this, newx, newy, w, h );
+    }
 }
 
-void wxCanvasObject::SetArea( wxRect rect )
+
+void wxCanvasObject::DragStart()
 {
-    m_area.x = rect.x;
-    m_area.y = rect.y;
-    m_area.width = rect.width;
-    m_area.height = rect.height;
+#if IMAGE_CANVAS
+#else
+    if (m_dragmode == DRAG_RECTANGLE)
+    {
+        this->SetVisible(FALSE);
+        wxTransformMatrix help;
+        double x = GetXMin();
+        double y = GetYMin();
+        double w = m_bbox.GetWidth();
+        double h = m_bbox.GetHeight();
+        m_admin->Update( this, x, y, w, h );
+        m_admin->UpdateNow();
+
+        wxRect recold=GetAbsoluteArea(help);
+        wxClientDC dc(m_admin->GetActive());
+        dc.SetPen(*wxBLACK_PEN);
+        dc.SetBrush(*wxTRANSPARENT_BRUSH);
+        dc.SetLogicalFunction(wxINVERT);
+        dc.DrawRectangle(recold);
+        dc.SetBrush(wxNullBrush);
+        dc.SetPen(wxNullPen);
+    }
+    else
+    {
+        this->SetVisible(FALSE);
+        wxTransformMatrix help;
+        double x = GetXMin();
+        double y = GetYMin();
+        double w = m_bbox.GetWidth();
+        double h = m_bbox.GetHeight();
+
+        wxRect recnew=GetAbsoluteArea(help);
+
+         //redraw in buffer what should be there without this object
+        m_admin->Update( this, x, y, w, h );
+        m_admin->GetActive()->Freeze();
+
+        //save the drawing (without the object itself to a bitmap)
+        m_atnewpos = wxBitmap(recnew.width,recnew.height);
+        wxMemoryDC dcm;
+        dcm.SelectObject(*m_admin->GetActive()->GetBuffer());
+        wxMemoryDC tmp;
+        tmp.SelectObject(m_atnewpos);
+        tmp.Blit(0,0,recnew.width,recnew.height,&dcm,recnew.x,recnew.y,wxCOPY,FALSE);
+        tmp.SelectObject(wxNullBitmap);
+        dcm.SelectObject(wxNullBitmap);
+    }
+#endif
 }
 
-void wxCanvasObject::Move( int x, int y )
+
+void wxCanvasObject::DragRelative( double x, double y)
 {
-    int old_x = m_area.x;
-    int old_y = m_area.y;
+#if IMAGE_CANVAS
+#else
+    if (m_dragmode == DRAG_RECTANGLE)
+    {
+        wxTransformMatrix help;
 
-    m_area.x = x;
-    m_area.y = y;
+        wxRect recold=GetAbsoluteArea(help);
 
-    if (!m_isControl)
+        TransLate(x,y);
+
+        wxRect recnew=GetAbsoluteArea(help);
+
+        wxClientDC dc(m_admin->GetActive());
+        dc.SetPen(*wxBLACK_PEN);
+        dc.SetBrush(*wxTRANSPARENT_BRUSH);
+        dc.SetLogicalFunction(wxINVERT);
+        dc.DrawRectangle(recold);
+        dc.DrawRectangle(recnew);
+        dc.SetBrush(wxNullBrush);
+        dc.SetPen(wxNullPen);
+    }
+    else
     {
-        // TODO: sometimes faster to merge into 1 Update or
-        // to break up into four
-        m_owner->Update( old_x, old_y, m_area.width, m_area.height );
-        m_owner->Update( x, y, m_area.width, m_area.height );
+        wxClientDC dc(m_admin->GetActive());
+        wxMemoryDC tmp;
+
+        wxTransformMatrix help;
+        wxRect recold=GetAbsoluteArea(help);
+
+        //restore what was there (without the object itself)
+        wxMemoryDC dcm;
+        dcm.SelectObject(*m_admin->GetActive()->GetBuffer());
+        tmp.SelectObject(m_atnewpos);
+        dcm.Blit(recold.x,recold.y,recold.width,recold.height,&tmp,0,0,wxCOPY,FALSE);
+
+        TransLate(x,y);
+
+        wxRect recnew=GetAbsoluteArea(help);
+
+        //save the contents of the buffer at the new position
+        tmp.Blit(0,0,recnew.width,recnew.height,&dcm,recnew.x,recnew.y,wxCOPY,FALSE);
+        tmp.SelectObject(wxNullBitmap);
+
+        //m_atnewpos = m_admin->GetActive()->GetBuffer()->GetSubBitmap( recnew );
+
+        this->SetVisible(TRUE);
+        //redraw object into the buffer
+        m_admin->GetActive()->SetDC(&dcm);
+        Render(&help,recnew.x,recnew.y,recnew.width,recnew.height);
+
+        //draw the union or seperate to the canvas
+        double leftu,rightu,bottomu,topu ;
+        leftu   = wxMin (recold.x, recnew.x ) ;
+        rightu  = wxMax (recold.x + recold.width, recnew.x + recnew.width ) ;
+        topu    = wxMin (recold.y, recnew.y) ;
+        bottomu = wxMax (recold.y + recold.height, recnew.y + recnew.height) ;
+
+        if ( rightu - leftu < 2*recold.width && bottomu - topu < 2*recold.height)
+        {
+            dc.Blit(leftu,topu,rightu - leftu,bottomu - topu,&dcm,leftu,topu,wxCOPY,FALSE);
+        }
+        else
+        {
+            //do them seperate
+            //first redraw what should be at the old position in the canvas
+            dc.Blit(recold.x,recold.y,recold.width,recold.height,&dcm,recold.x,recold.y,wxCOPY,FALSE);
+            //blit the new position of the object to the canvas
+            dc.Blit(recnew.x,recnew.y,recnew.width,recnew.height,&dcm,recnew.x,recnew.y,wxCOPY,FALSE);
+        }
+        dcm.SelectObject(wxNullBitmap);
+        this->SetVisible(FALSE);
     }
+#endif
+}
+
+
+void wxCanvasObject::DragEnd()
+{
+#if IMAGE_CANVAS
+#else
+    m_atnewpos = wxBitmap(0,0);
+    m_admin->GetActive()->Thaw();
+    this->SetVisible(TRUE);
+    double x = GetXMin();
+    double y = GetYMin();
+    double w = m_bbox.GetWidth();
+    double h = m_bbox.GetHeight();
+    m_admin->Update( this, x, y, w, h );
+    m_admin->UpdateNow();
+#endif
+}
+
+wxCanvasObject* wxCanvasObject::IsHitWorld( double x, double y, double margin )
+{
+    if ((x >= m_bbox.GetMinX()-margin) &&
+        (x <= m_bbox.GetMaxX()+margin) &&
+        (y >= m_bbox.GetMinY()-margin) &&
+        (y <= m_bbox.GetMaxY()+margin)
+       )
+        return this;
+    return (wxCanvasObject*) NULL;
 }
 
-bool wxCanvasObject::IsHit( int x, int y, int margin )
+wxCanvasObject* wxCanvasObject::Contains( wxCanvasObject* obj )
 {
-    return ((x >= m_area.x-margin) &&
-            (x <= m_area.x+m_area.width+margin) &&
-            (y >= m_area.y-margin) &&
-            (y <= m_area.y+m_area.height+margin));
+    if (obj == this)
+        return this;
+    return (wxCanvasObject*) NULL;
 }
 
 void wxCanvasObject::CaptureMouse()
 {
-    m_owner->SetCaptureMouse( this );
+    m_admin->GetActive()->SetCaptureMouse( this );
 }
 
 void wxCanvasObject::ReleaseMouse()
 {
-    m_owner->SetCaptureMouse( NULL );
+    m_admin->GetActive()->SetCaptureMouse( NULL );
 }
 
 bool wxCanvasObject::IsCapturedMouse()
 {
-    return m_owner->m_captureMouse==this;
+    return m_admin->GetActive()->GetCaptured()==this;
 }
 
 
-void wxCanvasObject::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
+void wxCanvasObject::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
 {
 }
 
-void wxCanvasObject::Recreate()
+void wxCanvasObject::CalcBoundingBox()
 {
 }
 
@@ -130,110 +412,209 @@ void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
 // wxCanvasObjectGroup
 //----------------------------------------------------------------------------
 
-wxCanvasObjectGroup::wxCanvasObjectGroup()
+wxCanvasObjectGroup::wxCanvasObjectGroup(double x, double y)
 {
-    m_validbounds = FALSE;
+    lworld.Translate(x,y);
+    //no objects make the bounding box the x,y and take care of it later
+    m_bbox.Expand(x,y);
 }
 
 wxCanvasObjectGroup::~wxCanvasObjectGroup()
 {
 }
 
-void wxCanvasObjectGroup::SetOwner(wxCanvas* canvas)
+void wxCanvasObjectGroup::PushEventHandler(wxEvtHandler *handler)
 {
-    m_owner=canvas;
+    wxCanvasObject::PushEventHandler(handler);
     wxNode *node = m_objects.First();
     while (node)
     {
         wxCanvasObject *obj = (wxCanvasObject*) node->Data();
 
-        obj->SetOwner(canvas);
+        obj->PushEventHandler(handler);
 
         node = node->Next();
     }
 }
 
-void wxCanvasObjectGroup::ExtendArea(double x, double y)
+wxEvtHandler *wxCanvasObjectGroup::PopEventHandler(bool deleteHandler)
 {
-    if (m_validbounds)
+    wxNode *node = m_objects.First();
+    while (node)
     {
-        if (x < m_minx) m_minx = x;
-        if (y < m_miny) m_miny = y;
-        if (x > m_maxx) m_maxx = x;
-        if (y > m_maxy) m_maxy = y;
+        wxCanvasObject *obj = (wxCanvasObject*) node->Data();
+
+        obj->PopEventHandler(deleteHandler);
+
+        node = node->Next();
     }
-    else
+    return wxCanvasObject::PopEventHandler(deleteHandler);
+}
+
+void wxCanvasObjectGroup::AppendEventHandler(wxEvtHandler *handler)
+{
+    wxCanvasObject::AppendEventHandler(handler);
+    wxNode *node = m_objects.First();
+    while (node)
+    {
+        wxCanvasObject *obj = (wxCanvasObject*) node->Data();
+
+        obj->AppendEventHandler(handler);
+
+        node = node->Next();
+    }
+}
+
+wxEvtHandler *wxCanvasObjectGroup::RemoveLastEventHandler(bool deleteHandler)
+{
+    wxNode *node = m_objects.First();
+    while (node)
+    {
+        wxCanvasObject *obj = (wxCanvasObject*) node->Data();
+
+        obj->RemoveLastEventHandler(deleteHandler);
+
+        node = node->Next();
+    }
+    return wxCanvasObject::RemoveLastEventHandler(deleteHandler);
+}
+
+void wxCanvasObjectGroup::TransLate( double x, double y )
+{
+    lworld.Translate(x,y);
+    CalcBoundingBox();
+}
+
+void wxCanvasObjectGroup::SetAdmin(wxCanvasAdmin* admin)
+{
+    m_admin=admin;
+    wxNode *node = m_objects.First();
+    while (node)
     {
-        m_validbounds = TRUE;
+        wxCanvasObject *obj = (wxCanvasObject*) node->Data();
+
+        obj->SetAdmin(admin);
 
-        m_minx = x;
-        m_miny = y;
-        m_maxx = x;
-        m_maxy = y;
+        node = node->Next();
     }
 }
 
 void wxCanvasObjectGroup::DeleteContents( bool flag)
 {
     m_objects.DeleteContents( flag );
-    m_validbounds = FALSE;
+    m_bbox.SetValid(FALSE);
+    CalcBoundingBox();
 }
 
 void wxCanvasObjectGroup::Prepend( wxCanvasObject* obj )
 {
     m_objects.Insert( obj );
-    m_validbounds = FALSE;
+    if (m_objects.First())
+        m_bbox.Expand(obj->GetBbox());
+    else
+    {
+        m_bbox.SetValid(FALSE);
+        CalcBoundingBox();
+    }
 }
 
 void wxCanvasObjectGroup::Append( wxCanvasObject* obj )
 {
     m_objects.Append( obj );
-    m_validbounds = FALSE;
+    if (m_objects.First())
+        m_bbox.Expand(obj->GetBbox());
+    else
+    {
+        m_bbox.SetValid(FALSE);
+        CalcBoundingBox();
+    }
 }
 
 void wxCanvasObjectGroup::Insert( size_t before, wxCanvasObject* obj )
 {
     m_objects.Insert( before, obj );
-    m_validbounds = FALSE;
+    m_bbox.SetValid(FALSE);
+    if (m_objects.First())
+        m_bbox.Expand(obj->GetBbox());
+    else
+    {
+        m_bbox.SetValid(FALSE);
+        CalcBoundingBox();
+    }
 }
 
 void wxCanvasObjectGroup::Remove( wxCanvasObject* obj )
 {
     m_objects.DeleteObject( obj );
-    m_validbounds = FALSE;
+    m_bbox.SetValid(FALSE);
+    CalcBoundingBox();
 }
 
-void wxCanvasObjectGroup::Recreate()
+void wxCanvasObjectGroup::CalcBoundingBox()
 {
-    m_validbounds = FALSE;
+    m_bbox.SetValid(FALSE);
     wxNode *node = m_objects.First();
     while (node)
     {
         wxCanvasObject *obj = (wxCanvasObject*) node->Data();
 
-        obj->Recreate();
-        ExtendArea(obj->GetX(),obj->GetY());
-        ExtendArea(obj->GetX()+obj->GetWidth(),obj->GetY()+obj->GetHeight());
 
+        obj->CalcBoundingBox();
+        wxBoundingBox tmp;
+        tmp=obj->GetBbox();
+        tmp.MapBbox(lworld);
+
+        m_bbox.Expand( tmp );
         node = node->Next();
     }
 }
 
-void wxCanvasObjectGroup::Render(int xabs, int yabs, int x, int y, int width, int height )
+void wxCanvasObjectGroup::Render(wxTransformMatrix* cworld, int x, int y, int width, int height )
 {
-    // cycle through all objects
+    if (!m_visible) return;
+
+    wxTransformMatrix backup = *cworld;
+    *cworld *= lworld;
+
     wxNode *node = m_objects.First();
+
+    if (!node) return;
+
+
+#ifdef CANVASDEBUG
+    wxRect absarea=GetAbsoluteArea(*cworld);
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetPen(*wxBLACK_PEN);
+    dc->SetBrush(*wxTRANSPARENT_BRUSH);
+    dc->DrawRectangle( absarea.x , absarea.y , absarea.width , absarea.height );
+    dc->SetBrush(wxNullBrush);
+    dc->SetPen(wxNullPen);
+#endif
+    //TODO the next will only work if all boundingboxes stay up to date (problem when mowing currently
+    /*
+    if (! ( wxMax(absarea.x, x) < wxMin(absarea.x + absarea.width , x + width ) &&
+            wxMax(absarea.y, y) < wxMin(absarea.y + absarea.height , y + height )
+          )
+       )
+        return;
+    */
+
+    // cycle through all objects
     while (node)
     {
         wxCanvasObject *obj = (wxCanvasObject*) node->Data();
 
-        if (!obj->IsControl())
+        if (!obj->IsControl() && obj->GetVisible())
         {
+
+            //get area at the absolute position
+            wxRect absareaobject=obj->GetAbsoluteArea(*cworld);
+
             // If we have 10.000 objects, we will go through
             // this 10.000 times for each update, so we have
             // to optimise carefully.
-            int clip_x = xabs + obj->GetX();
-            int clip_width = obj->GetWidth();
+            int clip_x = absareaobject.x;
+            int clip_width = absareaobject.width;
             if (clip_x < x)
             {
                 clip_width -= x-clip_x;
@@ -246,8 +627,8 @@ void wxCanvasObjectGroup::Render(int xabs, int yabs, int x, int y, int width, in
 
                 if (clip_width > 0)
                 {
-                    int clip_y = yabs + obj->GetY();
-                    int clip_height = obj->GetHeight();
+                    int clip_y = absareaobject.y;
+                    int clip_height = absareaobject.height;
                     if (clip_y < y)
                     {
                         clip_height -= y-clip_y;
@@ -259,7 +640,9 @@ void wxCanvasObjectGroup::Render(int xabs, int yabs, int x, int y, int width, in
                             clip_height = y+height-clip_y;
 
                         if (clip_height > 0)
-                            obj->Render(xabs,yabs, clip_x, clip_y, clip_width, clip_height );
+                        {
+                            obj->Render(cworld, clip_x, clip_y, clip_width, clip_height );
+                        }
                     }
                 }
             }
@@ -267,112 +650,176 @@ void wxCanvasObjectGroup::Render(int xabs, int yabs, int x, int y, int width, in
 
         node = node->Next();
     }
+    *cworld = backup;
 }
 
 void wxCanvasObjectGroup::WriteSVG( wxTextOutputStream &stream )
 {
 }
 
-bool wxCanvasObjectGroup::IsHit( int x, int y, int margin )
+wxCanvasObject* wxCanvasObjectGroup::IsHitWorld( double x, double y, double margin  )
 {
+    //KKKfirst check if within bbox
+    //will only work if they are always uptodate
+    //if (!m_bbox.PointInBox(x,y,margin))
+    //    return (wxCanvasObject*) NULL;
+
+    wxTransformMatrix inverse =  lworld;
+    double xh,yh;
+    inverse.Invert();
+    inverse.TransformPoint(x,y,xh,yh);
+
+    wxCanvasObject *obj=0;
     wxNode *node = m_objects.Last();
     while (node)
     {
-        wxCanvasObject *obj = (wxCanvasObject*) node->Data();
+        obj=(wxCanvasObject*) node->Data();
 
-        if (!obj->IsControl())
+        if (!obj->IsControl() )
         {
-            if (obj->IsHit(x,y,margin))
+            if (obj->IsHitWorld(x,y,margin))
             {
-                return TRUE;
+                return obj;
             }
         }
         node = node->Previous();
     }
-    return FALSE;
+
+    return (wxCanvasObject*) NULL;
 }
 
-wxCanvasObject* wxCanvasObjectGroup::IsHitObject( int x, int y, int margin )
+wxCanvasObject* wxCanvasObjectGroup::Contains( wxCanvasObject* obj )
 {
-    wxCanvasObject *obj=0;
-    wxNode *node = m_objects.Last();
+    wxCanvasObject* cobj;
+    wxNode *node = m_objects.First();
     while (node)
     {
-        obj=(wxCanvasObject*) node->Data();
+        cobj=(wxCanvasObject*) node->Data();
 
-        if (!obj->IsControl())
+        if (cobj->Contains(obj))
         {
-            if (obj->IsHit(x,y,margin))
-            {
-                return obj;
-            }
+            return obj;
         }
-        node = node->Previous();
+        node = node->Next();
     }
 
     return (wxCanvasObject*) NULL;
 }
 
+int wxCanvasObjectGroup::IndexOf( wxCanvasObject* obj )
+{
+    return m_objects.IndexOf( obj );
+}
+
+
+
 //----------------------------------------------------------------------------
-// wxCanvasObjectGroupRef
+// wxCanvasObjectRef
 //----------------------------------------------------------------------------
 
-wxCanvasObjectGroupRef::wxCanvasObjectGroupRef(double x, double y, wxCanvasObjectGroup* group)
+wxCanvasObjectRef::wxCanvasObjectRef(double x, double y, wxCanvasObject* obj)
    : wxCanvasObject()
 {
-    m_x = x;
-    m_y = y;
-    m_validbounds = FALSE;
-    m_group = group;
+     lworld.Translate(x,y);
+    m_obj = obj;
+
+    m_bbox.SetValid(FALSE);
+    wxBoundingBox tmp;
+    tmp=obj->GetBbox();
+    tmp.MapBbox(lworld);
+    m_bbox.Expand( tmp );
 }
 
-void wxCanvasObjectGroupRef::SetOwner(wxCanvas* canvas)
+void wxCanvasObjectRef::PushEventHandler(wxEvtHandler *handler)
 {
-    m_owner = canvas;
-    m_group->SetOwner(canvas);
+    wxCanvasObject::PushEventHandler(handler);
+    m_obj->PushEventHandler(handler);
 }
 
-void wxCanvasObjectGroupRef::ExtendArea(double x, double y)
+wxEvtHandler *wxCanvasObjectRef::PopEventHandler(bool deleteHandler)
 {
-    if (m_validbounds)
-    {
-        if (x < m_minx) m_minx = x;
-        if (y < m_miny) m_miny = y;
-        if (x > m_maxx) m_maxx = x;
-        if (y > m_maxy) m_maxy = y;
-    }
-    else
-    {
-        m_validbounds = TRUE;
+    m_obj->PopEventHandler(deleteHandler);
+    return wxCanvasObject::PopEventHandler(deleteHandler);
+}
 
-        m_minx = x;
-        m_miny = y;
-        m_maxx = x;
-        m_maxy = y;
-    }
+void wxCanvasObjectRef::AppendEventHandler(wxEvtHandler *handler)
+{
+    wxCanvasObject::AppendEventHandler(handler);
+    m_obj->AppendEventHandler(handler);
+}
+
+wxEvtHandler *wxCanvasObjectRef::RemoveLastEventHandler(bool deleteHandler)
+{
+    m_obj->RemoveLastEventHandler(deleteHandler);
+    return wxCanvasObject::RemoveLastEventHandler(deleteHandler);
+}
+
+void wxCanvasObjectRef::TransLate( double x, double y )
+{
+    lworld.Translate(x,y);
+    CalcBoundingBox();
+}
+
+wxCanvasObject* wxCanvasObjectRef::Contains( wxCanvasObject* obj )
+{
+    if (obj == this || m_obj->Contains(obj))
+        return this;
+
+    return (wxCanvasObject*) NULL;
+}
+
+
+void wxCanvasObjectRef::SetRotation(double rotation)
+{
+    lworld.SetRotation(rotation);
+    CalcBoundingBox();
+}
+
+void wxCanvasObjectRef::SetScale(double scalex,double scaley)
+{
+    lworld.Scale(scalex,scaley,lworld.GetValue(2,0),lworld.GetValue(2,1));
+    CalcBoundingBox();
 }
 
-void wxCanvasObjectGroupRef::Recreate()
+void wxCanvasObjectRef::SetAdmin(wxCanvasAdmin* admin)
 {
-    m_validbounds = FALSE;
-    m_group->Recreate();
-    ExtendArea(m_group->GetXMin(),m_group->GetYMin());
-    ExtendArea(m_group->GetXMax(),m_group->GetYMax());
+    m_admin = admin;
+    m_obj->SetAdmin(admin);
+}
+
+void wxCanvasObjectRef::CalcBoundingBox()
+{
+    m_bbox.SetValid(FALSE);
+    m_obj->CalcBoundingBox();
 
-    //set the area in pixels relative to the parent
-    SetArea( m_owner->GetDeviceX( m_x + m_minx ),
-             m_owner->GetDeviceY( m_y + m_miny ),
-             m_owner->GetDeviceWidth( m_maxx-m_minx ),
-             m_owner->GetDeviceHeight( m_maxy-m_miny ) );
+    wxBoundingBox tmp;
+    tmp=m_obj->GetBbox();
+    tmp.MapBbox(lworld);
+    m_bbox.Expand( tmp );
 }
 
-void wxCanvasObjectGroupRef::Render(int xabs, int yabs, int x, int y, int width, int height )
+void wxCanvasObjectRef::Render(wxTransformMatrix* cworld, int x, int y, int width, int height )
 {
-    xabs += m_area.x;
-    yabs += m_area.y;
+    if (!m_visible) return;
+
+    //get the absolute area (without the local matrix included)
+    //the boundingbox is relative to the parent.
+    wxRect absarea=GetAbsoluteArea(*cworld);
 
-    int clip_x = xabs + m_group->GetXMin();
-    int clip_width = m_group->GetXMax()-m_group->GetXMin();
+    wxTransformMatrix backup = *cworld;
+    *cworld *= lworld;
+
+#ifdef CANVASDEBUG
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetPen(*wxBLACK_PEN);
+    dc->SetBrush(*wxTRANSPARENT_BRUSH);
+    dc->DrawRectangle( absarea.x , absarea.y , absarea.width , absarea.height );
+    dc->SetBrush(wxNullBrush);
+    dc->SetPen(wxNullPen);
+#endif
+
+    int clip_x = absarea.x;
+    int clip_width = absarea.width;
     if (clip_x < x)
     {
         clip_width -= x-clip_x;
@@ -385,8 +832,8 @@ void wxCanvasObjectGroupRef::Render(int xabs, int yabs, int x, int y, int width,
 
         if (clip_width > 0)
         {
-            int clip_y = yabs + m_group->GetYMin();
-            int clip_height = m_group->GetYMax()-m_group->GetYMin();
+            int clip_y = absarea.y;
+            int clip_height = absarea.height;
             if (clip_y < y)
             {
                 clip_height -= y-clip_y;
@@ -398,295 +845,410 @@ void wxCanvasObjectGroupRef::Render(int xabs, int yabs, int x, int y, int width,
                     clip_height = y+height-clip_y;
 
                 if (clip_height > 0)
-                    m_group->Render(xabs,yabs, clip_x, clip_y, clip_width, clip_height );
+                    m_obj->Render(cworld, clip_x, clip_y, clip_width, clip_height );
             }
         }
     }
-}
 
-void wxCanvasObjectGroupRef::WriteSVG( wxTextOutputStream &stream )
-{
+    *cworld = backup;
 }
 
-bool wxCanvasObjectGroupRef::IsHit( int x, int y, int margin )
+void wxCanvasObjectRef::WriteSVG( wxTextOutputStream &stream )
 {
-    return m_group->IsHit(x-GetPosX(),y-GetPosY(),margin);
 }
 
-wxCanvasObject* wxCanvasObjectGroupRef::IsHitObject( int x, int y, int margin )
+wxCanvasObject* wxCanvasObjectRef::IsHitWorld( double x, double y, double margin )
 {
-    return m_group->IsHitObject(x-GetPosX(),y-GetPosY(),margin);
-}
+    //KKKfirst check if within bbox
+    //will only work if they are always uptodate
+    //if (!m_bbox.PointInBox(x,y,margin))
+    //    return (wxCanvasObject*) NULL;
 
-void wxCanvasObjectGroupRef::Move( int x, int y )
-{
-    m_x = x;
-    m_y = y;
+    wxTransformMatrix inverse =  lworld;
+    double xh,yh;
+    inverse.Invert();
+    inverse.TransformPoint(x,y,xh,yh);
 
-    int old_area_x = m_area.x;
-    int old_area_y = m_area.y;
+    if (m_obj->IsHitWorld(xh,yh,margin))
+        return this;
 
-    m_area.x=m_owner->GetDeviceX(  m_x + m_minx );
-    m_area.y=m_owner->GetDeviceY(  m_y + m_miny );
+    return (wxCanvasObject*) NULL;
+}
 
-       int leftu,rightu,bottomu,topu ;
-       leftu   = wxMin (m_area.x, old_area_x ) ;
-       rightu  = wxMax (old_area_x + m_area.width, m_area.x + m_area.width) ;
-       topu    = wxMin (m_area.y,old_area_y) ;
-       bottomu = wxMax (old_area_y + m_area.height, m_area.y + m_area.height) ;
 
-    if ( rightu - leftu < 2*m_area.width && bottomu - topu < 2*m_area.height )
-    {
-        m_owner->Update(leftu,topu,rightu - leftu,bottomu - topu);
-    }
-    else
-    {
-        m_owner->Update(old_area_x, old_area_y, m_area.width, m_area.height );
-        m_owner->Update( m_area.x, m_area.y, m_area.width, m_area.height );
-    }
-}
 
 //----------------------------------------------------------------------------
-// wxCanvasPolyline
+// wxCanvasRect
 //----------------------------------------------------------------------------
 
-wxCanvasPolyline::wxCanvasPolyline( int n,  wxPoint2DDouble points[])
+wxCanvasRect::wxCanvasRect( double x, double y, double w, double h , double radius )
    : wxCanvasObject()
 {
-    m_n = n;
-    m_points = points;
-    m_pen = *wxBLACK_PEN;
-}
-
-wxCanvasPolyline::~wxCanvasPolyline()
-{
-    delete m_points;
+    m_x = x;
+    m_y = y;
+    m_width = w;
+    m_height = h;
+    m_radius = radius;
+
+    m_brush = *wxBLACK_BRUSH;
+    m_pen = *wxTRANSPARENT_PEN;
+    CalcBoundingBox();
 }
 
-void wxCanvasPolyline::ExtendArea(double x, double y)
+void wxCanvasRect::TransLate( double x, double y )
 {
-    if (m_validbounds)
-    {
-        if (x < m_minx) m_minx = x;
-        if (y < m_miny) m_miny = y;
-        if (x > m_maxx) m_maxx = x;
-        if (y > m_maxy) m_maxy = y;
-    }
-    else
-    {
-        m_validbounds = TRUE;
-
-        m_minx = x;
-        m_miny = y;
-        m_maxx = x;
-        m_maxy = y;
-    }
+    m_x += x;
+    m_y += y;
+    CalcBoundingBox();
 }
 
-void wxCanvasPolyline::Recreate()
+void wxCanvasRect::CalcBoundingBox()
 {
-
-    m_validbounds=FALSE;
-    int i;
-    for (i=0; i < m_n;i++)
-    {
-        ExtendArea(m_points[i].m_x,m_points[i].m_y);
-    }
+    m_bbox.SetMin( m_x , m_y);
+    m_bbox.SetMax( m_x + m_width ,m_y + m_height );
 
     //include the pen width also
-    ExtendArea(m_minx -m_pen.GetWidth(),m_miny-m_pen.GetWidth());
-    ExtendArea(m_maxx+m_pen.GetWidth()*2,m_maxy+m_pen.GetWidth()*2);
-
-    //set the area in pixels relative to the parent
-    SetArea( m_owner->GetDeviceX(m_minx ),
-             m_owner->GetDeviceY(m_miny ),
-             m_owner->GetDeviceWidth( m_maxx-m_minx ),
-             m_owner->GetDeviceHeight( m_maxy-m_miny ) );
+//KKK    m_bbox.EnLarge(m_pen.GetWidth()+m_radius);
+    m_bbox.EnLarge(m_pen.GetWidth()/2);
 }
 
-void wxCanvasPolyline::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
+void wxCanvasRect::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
 {
-    int buffer_x = m_owner->GetBufferX();
-    int buffer_y = m_owner->GetBufferY();
+    if (!m_visible) return;
+
+#if IMAGE_CANVAS
+    wxImage *image = m_admin->GetActive()->GetBuffer();
 
-    int start_y = clip_y - buffer_y;
-    int end_y = clip_y+clip_height - buffer_y;
+    int start_y = clip_y;
+    int end_y = clip_y+clip_height;
 
-    int start_x = clip_x - buffer_x;
-    int end_x = clip_x+clip_width - buffer_x;
+    int start_x = clip_x;
+    int end_x = clip_x+clip_width;
 
-#if IMAGE_CANVAS
+    // speed up later
+    for (int y = start_y; y < end_y; y++)
+        for (int x = start_x; x < end_x; x++)
+        {
+            int red=m_brush.GetColour().Red();
+            int green=m_brush.GetColour().Green();
+            int blue=m_brush.GetColour().Blue();
+            image->SetRGB( x, y, red, green, blue );
+        }
 #else
-    wxPoint *cpoints = new wxPoint[m_n];
-    int i;
-    for (i = 0; i < m_n; i++)
+    if (cworld->GetRotation())
     {
-        cpoints[i].x = m_owner->GetDeviceX(m_points[i].m_x+xabs);
-        cpoints[i].y = m_owner->GetDeviceY(m_points[i].m_y+yabs);
+        wxPoint *cpoints = new wxPoint[4];
+        double x;
+        double y;
+        cworld->TransformPoint( m_x, m_y, x, y );
+        cpoints[0].x = m_admin->LogicalToDeviceX(x);
+        cpoints[0].y = m_admin->LogicalToDeviceY(y);
+        cworld->TransformPoint( m_x , m_y + m_height, x, y );
+        cpoints[1].x = m_admin->LogicalToDeviceX(x);
+        cpoints[1].y = m_admin->LogicalToDeviceY(y);
+        cworld->TransformPoint( m_x + m_width, m_y + m_height, x, y );
+        cpoints[2].x = m_admin->LogicalToDeviceX(x);
+        cpoints[2].y = m_admin->LogicalToDeviceY(y);
+        cworld->TransformPoint( m_x + m_width, m_y , x, y );
+        cpoints[3].x = m_admin->LogicalToDeviceX(x);
+        cpoints[3].y = m_admin->LogicalToDeviceY(y);
+
+        wxDC *dc = m_admin->GetActive()->GetDC();
+        dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
+        dc->SetBrush(m_brush);
+        int pw=m_pen.GetWidth();
+        m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
+        dc->SetPen(m_pen);
+        dc->DrawPolygon(4, cpoints, 0,0,wxWINDING_RULE);
+        delete [] cpoints;
+        dc->SetBrush(wxNullBrush);
+        dc->SetPen(wxNullPen);
+        dc->DestroyClippingRegion();
+        m_pen.SetWidth(pw);
+    }
+    else
+    {
+        wxDC *dc = m_admin->GetActive()->GetDC();
+        dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
+        dc->SetBrush(m_brush);
+        int pw=m_pen.GetWidth();
+        m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
+        dc->SetPen(m_pen);
+        //yes the whole not only the clipping region, because we have a pen also
+        int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
+        int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
+        int w = m_admin->LogicalToDeviceXRel( m_width );
+        int h = m_admin->LogicalToDeviceYRel( m_height );
+        int r = m_admin->LogicalToDeviceYRel( m_radius );
+        if (w > 0 && w < 1) w=1;
+        if (w < 0 && w > -1) w=-1;
+        if (h > 0 && h < 1) h=1;
+        if (h < 0 && h > -1) h=-1;
+        if (m_radius)
+            dc->DrawRoundedRectangle( x,y,w,h,r);
+        else
+            dc->DrawRectangle( x,y,w,h);
+        dc->SetBrush(wxNullBrush);
+        dc->SetPen(wxNullPen);
+        dc->DestroyClippingRegion();
+        m_pen.SetWidth(pw);
     }
-    wxMemoryDC *dc = m_owner->GetDC();
-    dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
-    dc->SetPen(m_pen);
-    dc->DrawLines(m_n, cpoints, 0,0);
-    delete [] cpoints;
-    dc->SetPen(wxNullPen);
-    dc->DestroyClippingRegion();
 #endif
 }
 
-void wxCanvasPolyline::WriteSVG( wxTextOutputStream &stream )
+void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
 {
 }
 
 //----------------------------------------------------------------------------
-// wxCanvasPolygon
+// wxCanvasCircle
 //----------------------------------------------------------------------------
 
-wxCanvasPolygon::wxCanvasPolygon( int n, wxPoint2DDouble points[])
+wxCanvasCircle::wxCanvasCircle( double x, double y, double radius )
    : wxCanvasObject()
 {
-    m_n = n;
-    m_points = points;
+    m_x = x;
+    m_y = y;
+    m_radius = radius;
+
     m_brush = *wxBLACK_BRUSH;
     m_pen = *wxTRANSPARENT_PEN;
+    CalcBoundingBox();
 }
 
-wxCanvasPolygon::~wxCanvasPolygon()
+void wxCanvasCircle::TransLate( double x, double y )
 {
-    delete m_points;
+    m_x += x;
+    m_y += y;
+    CalcBoundingBox();
 }
 
-void wxCanvasPolygon::ExtendArea(double x, double y)
+void wxCanvasCircle::CalcBoundingBox()
 {
-    if (m_validbounds)
-    {
-        if (x < m_minx) m_minx = x;
-        if (y < m_miny) m_miny = y;
-        if (x > m_maxx) m_maxx = x;
-        if (y > m_maxy) m_maxy = y;
-    }
-    else
-    {
-        m_validbounds = TRUE;
+    m_bbox.SetMin( m_x-m_radius , m_y-m_radius );
+    m_bbox.SetMax( m_x+m_radius , m_y+m_radius );
 
-        m_minx = x;
-        m_miny = y;
-        m_maxx = x;
-        m_maxy = y;
-    }
+    //include the pen width also
+    m_bbox.EnLarge(m_pen.GetWidth()/2);
+}
+
+void wxCanvasCircle::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    if (!m_visible) return;
+
+#if IMAGE_CANVAS
+#else
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
+    dc->SetBrush(m_brush);
+    int pw=m_pen.GetWidth();
+    m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
+    dc->SetPen(m_pen);
+    //yes the whole not only the clipping region, because we have a pen also
+    //and rotation on a circle is not important so only a shift with cworld
+    int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
+    int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
+    int radius = m_admin->LogicalToDeviceXRel( m_radius );
+    if (radius < 1) radius=1;
+    dc->DrawCircle( x,y,radius);
+    dc->SetBrush(wxNullBrush);
+    dc->SetPen(wxNullPen);
+    dc->DestroyClippingRegion();
+    m_pen.SetWidth(pw);
+#endif
 }
 
-void wxCanvasPolygon::Recreate()
+void wxCanvasCircle::WriteSVG( wxTextOutputStream &stream )
 {
+}
 
-    m_validbounds=FALSE;
-    int i;
-    for (i=0; i < m_n;i++)
+wxCanvasObject* wxCanvasCircle::IsHitWorld( double x, double y, double margin )
+{
+    if ((x >= m_bbox.GetMinX()-margin) &&
+        (x <= m_bbox.GetMaxX()+margin) &&
+        (y >= m_bbox.GetMinY()-margin) &&
+        (y <= m_bbox.GetMaxY()+margin)
+       )
     {
-        ExtendArea(m_points[i].m_x,m_points[i].m_y);
+        if (m_radius+m_pen.GetWidth()/2+margin > sqrt(pow(m_x-x,2)+pow(m_y-y,2)))
+            return this;
+        else
+            return (wxCanvasObject*) NULL;
     }
+    return (wxCanvasObject*) NULL;
+}
 
-    //include the pen width also
-    ExtendArea(m_minx -m_pen.GetWidth(),m_miny-m_pen.GetWidth());
-    ExtendArea(m_maxx+m_pen.GetWidth()*2,m_maxy+m_pen.GetWidth()*2);
+//----------------------------------------------------------------------------
+// wxCanvasEllipse
+//----------------------------------------------------------------------------
+
+wxCanvasEllipse::wxCanvasEllipse( double x, double y, double width, double height )
+   : wxCanvasObject()
+{
+    m_x = x;
+    m_y = y;
+    m_width = width;
+    m_height = height;
+
+    m_brush = *wxBLACK_BRUSH;
+    m_pen = *wxTRANSPARENT_PEN;
+    CalcBoundingBox();
+}
 
-    //set the area in pixels relative to the parent
-    SetArea( m_owner->GetDeviceX( m_minx ),
-             m_owner->GetDeviceY( m_miny ),
-             m_owner->GetDeviceWidth( m_maxx-m_minx ),
-             m_owner->GetDeviceHeight( m_maxy-m_miny ) );
+void wxCanvasEllipse::TransLate( double x, double y )
+{
+    m_x += x;
+    m_y += y;
+    CalcBoundingBox();
 }
 
-void wxCanvasPolygon::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
+void wxCanvasEllipse::CalcBoundingBox()
 {
-    int buffer_x = m_owner->GetBufferX();
-    int buffer_y = m_owner->GetBufferY();
+    m_bbox.SetMin( m_x, m_y );
+    m_bbox.SetMax( m_x+m_width , m_y+m_height );
 
-    int start_y = clip_y - buffer_y;
-    int end_y = clip_y+clip_height - buffer_y;
+    //include the pen width also
+    m_bbox.EnLarge(m_pen.GetWidth()/2);
+}
 
-    int start_x = clip_x - buffer_x;
-    int end_x = clip_x+clip_width - buffer_x;
+void wxCanvasEllipse::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    if (!m_visible) return;
 
 #if IMAGE_CANVAS
 #else
-    wxPoint *cpoints = new wxPoint[m_n];
-    int i;
-    for (i = 0; i < m_n; i++)
-    {
-        cpoints[i].x = m_owner->GetDeviceX(m_points[i].m_x+xabs);
-        cpoints[i].y = m_owner->GetDeviceY(m_points[i].m_y+yabs);
-    }
-    wxMemoryDC *dc = m_owner->GetDC();
-    dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
     dc->SetBrush(m_brush);
+    int pw=m_pen.GetWidth();
+    m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
     dc->SetPen(m_pen);
-    dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE);
-    delete [] cpoints;
+    int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
+    int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
+    int w = m_admin->LogicalToDeviceXRel( m_width );
+    int h = m_admin->LogicalToDeviceYRel( m_height );
+    if (w > 0 && w < 1) w=1;
+    if (w < 0 && w > -1) w=-1;
+    if (h > 0 && h < 1) h=1;
+    if (h < 0 && h > -1) h=-1;
+    dc->DrawEllipse( x,y,w,h);
     dc->SetBrush(wxNullBrush);
     dc->SetPen(wxNullPen);
     dc->DestroyClippingRegion();
+    m_pen.SetWidth(pw);
 #endif
 }
 
-void wxCanvasPolygon::WriteSVG( wxTextOutputStream &stream )
+void wxCanvasEllipse::WriteSVG( wxTextOutputStream &stream )
 {
 }
 
-
+wxCanvasObject* wxCanvasEllipse::IsHitWorld( double x, double y, double margin )
+{
+    if ((x >= m_bbox.GetMinX()-margin) &&
+        (x <= m_bbox.GetMaxX()+margin) &&
+        (y >= m_bbox.GetMinY()-margin) &&
+        (y <= m_bbox.GetMaxY()+margin)
+       )
+    {
+        double a=(m_width+m_pen.GetWidth())/2+margin ;
+        double b=(m_height+m_pen.GetWidth())/2+margin;
+        double c=pow((m_x+m_width/2-x)/a,2)+pow((m_y+m_height/2-y)/b,2);
+        if ( 1 > c)
+            return this;
+        else
+            return (wxCanvasObject*) NULL;
+    }
+    return (wxCanvasObject*) NULL;
+}
 
 //----------------------------------------------------------------------------
-// wxCanvasRect
+// wxCanvasEllipticArc
 //----------------------------------------------------------------------------
 
-wxCanvasRect::wxCanvasRect( double x, double y, double w, double h )
+wxCanvasEllipticArc::wxCanvasEllipticArc( double x, double y, double width, double height, double start, double end )
    : wxCanvasObject()
 {
     m_x = x;
     m_y = y;
-    m_width = w;
-    m_height = h;
+    m_width  = width;
+    m_height = height;
+    m_start  = start;
+    m_end    = end;
 
     m_brush = *wxBLACK_BRUSH;
     m_pen = *wxTRANSPARENT_PEN;
+    CalcBoundingBox();
 }
 
-void wxCanvasRect::Recreate()
+void wxCanvasEllipticArc::TransLate( double x, double y )
 {
-    SetArea( m_owner->GetDeviceX( m_x ),
-             m_owner->GetDeviceY( m_y ),
-             m_owner->GetDeviceWidth( m_width ),
-             m_owner->GetDeviceHeight( m_height ) );
+    m_x += x;
+    m_y += y;
+    CalcBoundingBox();
 }
 
-void wxCanvasRect::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
+void wxCanvasEllipticArc::CalcBoundingBox()
 {
-    int buffer_x = m_owner->GetBufferX();
-    int buffer_y = m_owner->GetBufferY();
+    m_bbox.SetMin( m_x, m_y );
+    m_bbox.SetMax( m_x+m_width , m_y+m_height );
 
-#if IMAGE_CANVAS
-    wxImage *image = m_owner->GetBuffer();
-    
-    int start_y = clip_y - buffer_y;
-    int end_y = clip_y+clip_height - buffer_y;
+    //include the pen width also
+    m_bbox.EnLarge(m_pen.GetWidth()/2);
+}
 
-    int start_x = clip_x - buffer_x;
-    int end_x = clip_x+clip_width - buffer_x;
+void wxCanvasEllipticArc::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    if (!m_visible) return;
 
-    // speed up later
-    for (int y = start_y; y < end_y; y++)
-        for (int x = start_x; x < end_x; x++)
-            image->SetRGB( x, y, m_red, m_green, m_blue );
+#if IMAGE_CANVAS
 #else
-    wxMemoryDC *dc = m_owner->GetDC();
-    dc->SetPen( m_pen );
-    dc->SetBrush( m_brush );
-    dc->DrawRectangle( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height );
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
+    dc->SetBrush(m_brush);
+    int pw=m_pen.GetWidth();
+    m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
+    dc->SetPen(m_pen);
+    int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
+    int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
+    int w = m_admin->LogicalToDeviceXRel( m_width );
+    int h = m_admin->LogicalToDeviceYRel( m_height );
+    if (w > 0 && w < 1) w=1;
+    if (w < 0 && w > -1) w=-1;
+    if (h > 0 && h < 1) h=1;
+    if (h < 0 && h > -1) h=-1;
+    if (m_admin->GetActive()->GetYaxis())
+        dc->DrawEllipticArc( x,y,w,h,-m_end,-m_start);
+    else
+        dc->DrawEllipticArc( x,y,w,h,m_start,m_end);
+    dc->SetBrush(wxNullBrush);
+    dc->SetPen(wxNullPen);
+    dc->DestroyClippingRegion();
+    m_pen.SetWidth(pw);
 #endif
 }
 
-void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
+void wxCanvasEllipticArc::WriteSVG( wxTextOutputStream &stream )
+{
+}
+
+wxCanvasObject* wxCanvasEllipticArc::IsHitWorld( double x, double y, double margin )
 {
+    if ((x >= m_bbox.GetMinX()-margin) &&
+        (x <= m_bbox.GetMaxX()+margin) &&
+        (y >= m_bbox.GetMinY()-margin) &&
+        (y <= m_bbox.GetMaxY()+margin)
+       )
+    {
+        double a=(m_width+m_pen.GetWidth())/2+margin ;
+        double b=(m_height+m_pen.GetWidth())/2+margin;
+        double c=pow((m_x+m_width/2-x)/a,2)+pow((m_y+m_height/2-y)/b,2);
+        if ( 1 > c)
+            return this;
+        else
+            return (wxCanvasObject*) NULL;
+    }
+    return (wxCanvasObject*) NULL;
 }
 
 //----------------------------------------------------------------------------
@@ -702,47 +1264,58 @@ wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2 )
     m_y2 = y2;
 
     m_pen = *wxBLACK_PEN;
+    CalcBoundingBox();
 }
 
-void wxCanvasLine::Recreate()
+void wxCanvasLine::TransLate( double x, double y )
 {
-    int x1 = m_owner->GetDeviceX( m_x1 );
-    int y1 = m_owner->GetDeviceY( m_y1 );
-    int x2 = m_owner->GetDeviceX( m_x2 );
-    int y2 = m_owner->GetDeviceY( m_y2 );
-    if (x1 > x2)
-    {
-        int tmp = x1;
-        x1 = x2;
-        x2 = tmp;
-    }
-    if (y1 > y2)
-    {
-        int tmp = y1;
-        y1 = y2;
-        y2 = tmp;
-    }
-    SetArea( x1, y1, x2-x1+1, y2-y1+1 );
+    m_x1 += x;
+    m_y1 += y;
+    m_x2 += x;
+    m_y2 += y;
+    CalcBoundingBox();
+}
+
+void wxCanvasLine::CalcBoundingBox()
+{
+    m_bbox.SetMin( m_x1 , m_y1);
+    m_bbox.SetMax( m_x2 , m_y2);
+
+    //include the pen width also
+    m_bbox.EnLarge(m_pen.GetWidth()/2);
 }
 
-void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
+void wxCanvasLine::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
 {
-    int buffer_x = m_owner->GetBufferX();
-    int buffer_y = m_owner->GetBufferY();
+    if (!m_visible) return;
 
-    int x1 = xabs + m_owner->GetDeviceX( m_x1 );
-    int y1 = yabs + m_owner->GetDeviceY( m_y1 );
-    int x2 = xabs + m_owner->GetDeviceX( m_x2 );
-    int y2 = yabs + m_owner->GetDeviceY( m_y2 );
+    double x1,y1,x2,y2;
+    cworld->TransformPoint( m_x1, m_y1, x1, y1 );
+    cworld->TransformPoint( m_x2, m_y2, x2, y2 );
+    x1 = m_admin->LogicalToDeviceX( x1 );
+    y1 = m_admin->LogicalToDeviceY( y1 );
+    x2 = m_admin->LogicalToDeviceX( x2 );
+    y2 = m_admin->LogicalToDeviceY( y2 );
 
 #if IMAGE_CANVAS
-    wxImage *image = m_owner->GetBuffer();
-    if ((m_area.width == 0) && (m_area.height == 0))
+    wxRect tmparea;
+    tmparea.x = m_admin->LogicalToDeviceXRel( m_bbox.GetMinX());
+    tmparea.y = m_admin->LogicalToDeviceYRel( m_bbox.GetMinY());
+    tmparea.width = m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() );
+    tmparea.height = m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() );
+    wxImage *image = m_admin->GetActive()->GetBuffer();
+    if ((tmparea.width == 0) && (tmparea.height == 0))
     {
-        image->SetRGB( m_area.x-buffer_x, m_area.y-buffer_y, m_red, m_green, m_blue );
+        int red=m_pen.GetColour().Red();
+        int green=m_pen.GetColour().Green();
+        int blue=m_pen.GetColour().Blue();
+        image->SetRGB( tmparea.x, tmparea.y, red, green, blue );
     }
     else
     {
+        int red=m_pen.GetColour().Red();
+        int green=m_pen.GetColour().Green();
+        int blue=m_pen.GetColour().Blue();
         wxInt32 d, ii, jj, di, ai, si, dj, aj, sj;
         di = x1 - x2;
         ai = abs(di) << 1;
@@ -764,7 +1337,7 @@ void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_w
                 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
                     (jj >= clip_y) && (jj < clip_y+clip_height))
                 {
-                    image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green );
+                    image->SetRGB( ii, jj, red, blue, green );
                 }
                 if (d >= 0)
                 {
@@ -785,7 +1358,7 @@ void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_w
                 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
                     (jj >= clip_y) && (jj < clip_y+clip_height))
                 {
-                    image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green );
+                    image->SetRGB( ii, jj, red, blue, green );
                 }
                 if (d >= 0)
                 {
@@ -798,12 +1371,15 @@ void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_w
         }
     }
 #else
-    wxMemoryDC *dc = m_owner->GetDC();
-    dc->SetClippingRegion( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height );
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetClippingRegion( clip_x, clip_y, clip_width, clip_height );
+    int pw=m_pen.GetWidth();
+    m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
     dc->SetPen( m_pen );
-    dc->DrawLine( x1-buffer_x, y1-buffer_y, x2-buffer_x, y2-buffer_y );
+    dc->DrawLine( x1, y1, x2, y2 );
 
     dc->DestroyClippingRegion();
+    m_pen.SetWidth(pw);
 #endif
 }
 
@@ -812,6 +1388,25 @@ void wxCanvasLine::WriteSVG( wxTextOutputStream &stream )
     // no idea
 }
 
+wxCanvasObject* wxCanvasLine::IsHitWorld( double x, double y, double margin )
+{
+    if ((x >= m_bbox.GetMinX()-margin) &&
+        (x <= m_bbox.GetMaxX()+margin) &&
+        (y >= m_bbox.GetMinY()-margin) &&
+        (y <= m_bbox.GetMaxY()+margin)
+       )
+    {
+        wxLine line1(m_x1,m_y1,m_x2,m_y2);
+        wxPoint2DDouble P=wxPoint2DDouble(x,y);
+        double distance;
+        if (line1.PointInLine(P,distance,m_pen.GetWidth()/2+margin) == R_IN_AREA)
+            return this;
+        else
+            return (wxCanvasObject*) NULL;
+    }
+    return (wxCanvasObject*) NULL;
+}
+
 //----------------------------------------------------------------------------
 // wxCanvasImage
 //----------------------------------------------------------------------------
@@ -825,83 +1420,159 @@ wxCanvasImage::wxCanvasImage( const wxImage &image, double x, double y, double w
     m_height = h;
 
     m_image = image;
+
+    m_orgw=m_image.GetWidth();
+    m_orgh=m_image.GetHeight();
+
     m_isImage = TRUE;
+    m_visible = FALSE;
+//KKK    m_visible=TRUE;
+    CalcBoundingBox();
 }
 
-void wxCanvasImage::Recreate()
+void wxCanvasImage::TransLate( double x, double y )
 {
-    SetArea( m_owner->GetDeviceX( m_x ),
-             m_owner->GetDeviceY( m_y ),
-             m_owner->GetDeviceWidth( m_width ),
-             m_owner->GetDeviceHeight( m_height ) );
+    m_x += x;
+    m_y += y;
+    CalcBoundingBox();
+}
+
+void wxCanvasImage::CalcBoundingBox()
+{
+    m_bbox.SetMin( m_x , m_y);
+    m_bbox.SetMax( m_x + m_width , m_y + m_height);
+}
+
+void wxCanvasImage::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    if (!m_visible) return;
+
+    wxRect tmparea;
+
+    tmparea.x = m_admin->LogicalToDeviceXRel( m_bbox.GetMinX());
+    tmparea.y = m_admin->LogicalToDeviceYRel( m_bbox.GetMinY());
+    tmparea.width = m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() );
+    tmparea.height = m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() );
+
+    double x;
+    double y;
+    cworld->TransformPoint( m_x, m_y, x, y );
+    x = m_admin->LogicalToDeviceX(x);
+    y = m_admin->LogicalToDeviceY(y);
+
 
 #if IMAGE_CANVAS
-    if ((m_area.width == m_image.GetWidth()) &&
-        (m_area.width == m_image.GetWidth()))
+    if ((clip_x == xabs + tmparea.x) &&
+        (clip_y == yabs + tmparea.y) &&
+        (clip_width == tmparea.width) &&
+        (clip_height == tmparea.height))
     {
-        m_tmp = m_image;
+        m_admin->GetActive()->GetBuffer()->Paste( m_tmp, clip_x, clip_y );
     }
     else
     {
-        m_tmp = m_image.Scale( m_area.width, m_area.height );
+        // local coordinates
+        int start_x = clip_x - (xabs + tmparea.x);
+        int start_y = clip_y - (yabs + tmparea.y);
+
+        wxRect rect( start_x, start_y, clip_width, clip_height );
+        wxImage sub_image( m_tmp.GetSubImage( rect ) );
+        m_admin->GetActive()->GetBuffer()->Paste( sub_image, clip_x, clip_y );
     }
 #else
-    if ((m_area.width == m_image.GetWidth()) &&
-        (m_area.width == m_image.GetWidth()))
+    if (  m_orgw*5 < m_admin->LogicalToDeviceXRel( m_bbox.GetWidth()  ) ||
+          m_orgw/5 > m_admin->LogicalToDeviceXRel( m_bbox.GetWidth()  ) ||
+          m_orgh*5 < m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() ) ||
+          m_orgh/5 > m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() )
+       )
+    {
+        wxDC *dc = m_admin->GetActive()->GetDC();
+        dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
+        dc->SetBrush(*wxTRANSPARENT_BRUSH);
+        dc->SetPen(*wxBLACK_PEN);
+        //yes the whole not only the clipping region, because we have a pen also
+        int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
+        int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
+        int w = m_admin->LogicalToDeviceXRel( m_width );
+        int h = m_admin->LogicalToDeviceYRel( m_height );
+        if (w < 1) w=1;
+        if (h < 1) h=1;
+        dc->DrawRectangle( x,y,w,h);
+        dc->SetBrush(wxNullBrush);
+        dc->SetPen(wxNullPen);
+        dc->DestroyClippingRegion();
+        return;
+    }
+
+    if ((m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() ) == m_image.GetWidth()) &&
+        (m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() ) == m_image.GetHeight()))
     {
-        m_tmp = m_image.ConvertToBitmap();
+        m_tmp = m_image;
     }
     else
     {
-        wxImage tmp( m_image.Scale( m_area.width, m_area.height ) );
-        m_tmp = tmp.ConvertToBitmap();
+        m_tmp = m_image.Scale( m_admin->LogicalToDeviceXRel( m_bbox.GetWidth()),
+                               m_admin->LogicalToDeviceYRel( m_bbox.GetHeight()) );
     }
-#endif
-}
 
-void wxCanvasImage::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
-{
-    int buffer_x = m_owner->GetBufferX();
-    int buffer_y = m_owner->GetBufferY();
+    wxBitmap bmp;
+//    wxPoint centr(m_admin->LogicalToDeviceX(m_x),m_admin->LogicalToDeviceY(m_y));
+    wxPoint centr(0,0);
 
-#if IMAGE_CANVAS
-    if ((clip_x == xabs + m_area.x) &&
-        (clip_y == yabs + m_area.y) &&
-        (clip_width == m_area.width) &&
-        (clip_height == m_area.height))
+    if (cworld->GetRotation())
     {
-        m_owner->GetBuffer()->Paste( m_tmp, clip_x-buffer_x, clip_y-buffer_y );
+        bmp=m_tmp.Rotate(-cworld->GetRotation()/180.0 * pi,centr, TRUE,  NULL).ConvertToBitmap();
     }
     else
     {
-        // local coordinates
-        int start_x = clip_x - (xabs + m_area.x);
-        int start_y = clip_y - (yabs + m_area.y);
-
-        wxRect rect( start_x, start_y, clip_width, clip_height );
-        wxImage sub_image( m_tmp.GetSubImage( rect ) );
-        m_owner->GetBuffer()->Paste( sub_image, clip_x-buffer_x, clip_y-buffer_y );
+        bmp = m_tmp.ConvertToBitmap();
     }
-#else
-    wxMemoryDC *dc = m_owner->GetDC();
 
-    if ((clip_x == xabs + m_area.x) &&
-        (clip_y == yabs + m_area.y) &&
-        (clip_width == m_area.width) &&
-        (clip_height == m_area.height))
+    wxDC *dc = m_admin->GetActive()->GetDC();
+
+    wxPoint centr2;
+    if (cworld->GetRotation()> 0)
     {
-        dc->DrawBitmap( m_tmp, clip_x-buffer_x, clip_y-buffer_y, TRUE );
+        centr2.x= (int) (x+m_height*sin(-cworld->GetRotation()/180.0 * pi));
+        centr2.y= (int) y;
     }
     else
     {
-        // local coordinates
-        int start_x = clip_x - (xabs + m_area.x);
-        int start_y = clip_y - (yabs + m_area.y);
+        centr2.x= (int) x;
+        centr2.y= (int) (y-m_width*sin(-cworld->GetRotation()/180.0 * pi));
+    }
 
-        // Clipping region faster ?
-        wxRect rect( start_x, start_y, clip_width, clip_height );
-        wxBitmap sub_bitmap( m_tmp.GetSubBitmap( rect ) );
-        dc->DrawBitmap( sub_bitmap, clip_x-buffer_x, clip_y-buffer_y, TRUE );
+    if (cworld->GetRotation() != 0)
+    {
+        //TODO clipping not right
+            dc->DrawBitmap(bmp,centr2,TRUE );
+//        dc->DrawPoint(centr2);
+//        dc->DrawPoint(x,y);
+    }
+    else
+    {
+        //TODO clipping not right
+//        dc->DrawPoint(centr2);
+//        dc->DrawPoint(x,y);
+
+        if ((clip_x == x) &&
+            (clip_y == y) &&
+            (clip_width == tmparea.width) &&
+            (clip_height == tmparea.height))
+        {
+            dc->DrawBitmap( m_tmp, clip_x, clip_y, TRUE );
+        }
+        else
+        {
+            int start_x = clip_x - (int)x;
+            int start_y = clip_y - (int)y;
+
+            //dc->DrawBitmap( bmp, x, y, TRUE );
+            wxMemoryDC dcm;
+            dcm.SelectObject(bmp);
+            dc->Blit(clip_x, clip_y,clip_width, clip_height,&dcm,start_x,start_y,wxCOPY,TRUE);
+            dcm.SelectObject(wxNullBitmap);
+        }
     }
 #endif
 }
@@ -920,6 +1591,39 @@ wxCanvasControl::wxCanvasControl( wxWindow *control )
 {
     m_isControl = TRUE;
     m_control = control;
+    CalcBoundingBox();
+}
+
+double wxCanvasControl::GetPosX()
+{
+    int x,y ;
+    m_control->GetPosition( &x, &y );
+    return m_admin->DeviceToLogicalX(x);
+}
+
+double wxCanvasControl::GetPosY()
+{
+    int x,y ;
+    m_control->GetPosition( &x, &y );
+    return m_admin->DeviceToLogicalY(y);
+}
+
+void wxCanvasControl::SetPosXY( double x, double y)
+{
+    int xd = m_admin->LogicalToDeviceX(x);
+    int yd = m_admin->LogicalToDeviceY(y);
+    m_control->Move(xd,yd);
+}
+
+
+void wxCanvasControl::TransLate( double x, double y )
+{
+    int xdo,ydo;
+    m_control->GetPosition( &xdo, &ydo );
+    int xd = m_admin->LogicalToDeviceX(x)-xdo;
+    int yd = m_admin->LogicalToDeviceY(y)-ydo;
+    m_control->Move(xd,yd);
+    CalcBoundingBox();
 }
 
 wxCanvasControl::~wxCanvasControl()
@@ -927,15 +1631,21 @@ wxCanvasControl::~wxCanvasControl()
     m_control->Destroy();
 }
 
-void wxCanvasControl::Recreate()
+void wxCanvasControl::CalcBoundingBox()
 {
-    m_control->GetSize( &m_area.width, &m_area.height );
-    m_control->GetPosition( &m_area.x, &m_area.y );
+    wxRect tmparea;
+
+    m_control->GetSize( &tmparea.width, &tmparea.height );
+    m_control->GetPosition( &tmparea.x, &tmparea.y );
+
+    m_bbox.SetMin( tmparea.x , tmparea.y);
+    m_bbox.SetMax( tmparea.x + tmparea.width , tmparea.y + tmparea.height);
+
 }
 
-void wxCanvasControl::Move( int x, int y )
+void wxCanvasControl::MoveRelative( double x, double y )
 {
-    m_control->Move( x, y );
+    m_control->Move( m_admin->LogicalToDeviceX(x),  m_admin->LogicalToDeviceX(y) );
 }
 
 //----------------------------------------------------------------------------
@@ -983,6 +1693,7 @@ wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxSt
                               96,    // screen dpi
                               96 );
 #endif
+    CalcBoundingBox();
 }
 
 wxCanvasText::~wxCanvasText()
@@ -1007,30 +1718,72 @@ void wxCanvasText::SetFlag( int flag )
     m_flag = flag;
 }
 
-void wxCanvasText::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
+void wxCanvasText::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
 {
+    if (!m_visible) return;
+
+    wxRect tmparea;
+    tmparea.x = m_admin->LogicalToDeviceX( m_bbox.GetMinX());
+    tmparea.y = m_admin->LogicalToDeviceY( m_bbox.GetMinY());
+    tmparea.width = m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() );
+    tmparea.height = m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() );
+
+    m_alpha = new unsigned char[tmparea.width*tmparea.height];
+    memset( m_alpha, 0, tmparea.width*tmparea.height );
+
     if (!m_alpha) return;
 
-    int buffer_x = m_owner->GetBufferX();
-    int buffer_y = m_owner->GetBufferY();
-    
+#if wxUSE_FREETYPE
+    FT_Face face = ((wxFaceData*)m_faceData)->m_face;
+    FT_GlyphSlot slot = face->glyph;
+    int pen_x = 0;
+    int pen_y = m_size;
+
+    for (int n = 0; n < (int)m_text.Len(); n++)
+    {
+        FT_UInt index = FT_Get_Char_Index( face, m_text[(unsigned int)n] );
+
+        int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
+        if (error) continue;
+
+        error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+        if (error) continue;
+
+        FT_Bitmap *bitmap = &slot->bitmap;
+        unsigned char* buffer = bitmap->buffer;
+        for (int y = 0; y < bitmap->rows; y++)
+            for (int x = 0; x < bitmap->width; x++)
+            {
+                unsigned char alpha = buffer[ y*bitmap->pitch + x ];
+                if (alpha == 0) continue;
+
+                int xx = pen_x + slot->bitmap_left + x;
+                int yy = pen_y - slot->bitmap_top + y;
+                m_alpha[ yy * tmparea.width + xx ] = alpha;
+            }
+
+        pen_x += slot->advance.x >> 6;
+        pen_y += slot->advance.y >> 6;
+    }
+#endif
+
 #if IMAGE_CANVAS
-    wxImage *image = m_owner->GetBuffer();
+    wxImage *image = m_admin->GetActive()->GetBuffer();
 
     // local coordinates
-    int start_x = clip_x - m_area.x;
+    int start_x = clip_x - tmparea.x;
     int end_x = clip_width + start_x;
-    int start_y = clip_y - m_area.y;
+    int start_y = clip_y - tmparea.y;
     int end_y = clip_height + start_y;
 
     for (int y = start_y; y < end_y; y++)
         for (int x = start_x; x < end_x; x++)
         {
-            int alpha = m_alpha[y*m_area.width + x];
+            int alpha = m_alpha[y*tmparea.width + x];
             if (alpha)
             {
-                int image_x = m_area.x+x - buffer_x;
-                int image_y = m_area.y+y - buffer_y;
+                int image_x = tmparea.x+x;
+                int image_y = tmparea.y+y;
                 if (alpha == 255)
                 {
                     image->SetRGB( image_x, image_y, m_red, m_green, m_blue );
@@ -1052,22 +1805,22 @@ void wxCanvasText::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_w
             }
         }
 #else
-    wxBitmap *bitmap = m_owner->GetBuffer();
-    wxRect sub_rect( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height );
+    wxBitmap *bitmap = m_admin->GetActive()->GetBuffer();
+    wxRect sub_rect( clip_x, clip_y, clip_width, clip_height );
     wxBitmap sub_bitmap( bitmap->GetSubBitmap( sub_rect ) );
-    
+
     wxImage image( sub_bitmap );
 
     // local coordinates
-    int start_x = clip_x - m_area.x;
+    int start_x = clip_x - tmparea.x;
     int end_x = clip_width + start_x;
-    int start_y = clip_y - m_area.y;
+    int start_y = clip_y - tmparea.y;
     int end_y = clip_height + start_y;
 
     for (int y = start_y; y < end_y; y++)
         for (int x = start_x; x < end_x; x++)
         {
-            int alpha = m_alpha[y*m_area.width + x];
+            int alpha = m_alpha[y*tmparea.width + x];
             if (alpha)
             {
                 int image_x = x - start_x;
@@ -1092,11 +1845,11 @@ void wxCanvasText::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_w
                 image.SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
             }
         }
-   
+
    sub_bitmap = image.ConvertToBitmap();
-   
-   wxMemoryDC *dc = m_owner->GetDC();
-   dc->DrawBitmap( sub_bitmap, clip_x-buffer_x, clip_y-buffer_y );
+
+   wxDC *dc = m_admin->GetActive()->GetDC();
+   dc->DrawBitmap( sub_bitmap, clip_x, clip_y );
 #endif
 }
 
@@ -1104,60 +1857,31 @@ void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
 {
 }
 
-void wxCanvasText::Recreate()
+void wxCanvasText::TransLate( double x, double y )
 {
-    if (m_alpha) delete [] m_alpha;
+    m_x += x;
+    m_y += y;
+    CalcBoundingBox();
+}
 
-    m_area.x = m_owner->GetDeviceX( m_x );
-    m_area.y = m_owner->GetDeviceY( m_y );
+void wxCanvasText::CalcBoundingBox()
+{
+    if (m_alpha) delete [] m_alpha;
 
-    m_area.width = 100;                   // TODO calculate length
-    m_area.height = m_size + (m_size/2);  // TODO space for sub-baseline (pgypq)
-    m_alpha = new unsigned char[m_area.width*m_area.height];
-    memset( m_alpha, 0, m_area.width*m_area.height );
+    m_bbox.SetMin( m_x , m_y);
+    m_bbox.SetMax( m_x + 100 , m_y + m_size + (m_size/2));
 
-#if wxUSE_FREETYPE
-    FT_Face face = ((wxFaceData*)m_faceData)->m_face;
-    FT_GlyphSlot slot = face->glyph;
-    int pen_x = 0;
-    int pen_y = m_size;
 
-    for (int n = 0; n < (int)m_text.Len(); n++)
-    {
-        FT_UInt index = FT_Get_Char_Index( face, m_text[n] );
+}
 
-        int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
-        if (error) continue;
+//----------------------------------------------------------------------------
+// wxCanvas
+//----------------------------------------------------------------------------
 
-        error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
-        if (error) continue;
+IMPLEMENT_CLASS(wxCanvas,wxWindow)
 
-        FT_Bitmap *bitmap = &slot->bitmap;
-        unsigned char* buffer = bitmap->buffer;
-        for (int y = 0; y < bitmap->rows; y++)
-            for (int x = 0; x < bitmap->width; x++)
-            {
-                unsigned char alpha = buffer[ y*bitmap->pitch + x ];
-                if (alpha == 0) continue;
-
-                int xx = pen_x + slot->bitmap_left + x;
-                int yy = pen_y - slot->bitmap_top + y;
-                m_alpha[ yy * m_area.width + xx ] = alpha;
-            }
-
-        pen_x += slot->advance.x >> 6;
-        pen_y += slot->advance.y >> 6;
-    }
-#endif
-}
-
-//----------------------------------------------------------------------------
-// wxCanvas
-//----------------------------------------------------------------------------
-
-IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow)
-
-BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow)
+BEGIN_EVENT_TABLE(wxCanvas,wxWindow)
+    EVT_SCROLLWIN( wxCanvas::OnScroll )
     EVT_CHAR( wxCanvas::OnChar )
     EVT_PAINT( wxCanvas::OnPaint )
     EVT_SIZE( wxCanvas::OnSize )
@@ -1168,26 +1892,22 @@ BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow)
     EVT_ERASE_BACKGROUND( wxCanvas::OnEraseBackground )
 END_EVENT_TABLE()
 
-wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
+wxCanvas::wxCanvas( wxCanvasAdmin* admin, wxWindow *parent, wxWindowID id,
     const wxPoint &position, const wxSize& size, long style ) :
-    wxScrolledWindow( parent, id, position, size, style )
+    wxWindow( parent, id, position, size, style )
 {
-    m_bufferX = 0;
-    m_bufferY = 0;
+    m_admin = admin;
+    m_admin->Append(this);
     m_needUpdate = FALSE;
-    m_red = 0;
-    m_green = 0;
-    m_blue = 0;
+    m_background = *wxWHITE;
     m_lastMouse = (wxCanvasObject*)NULL;
     m_captureMouse = (wxCanvasObject*)NULL;
     m_frozen = TRUE;
     m_oldDeviceX = 0;
     m_oldDeviceY = 0;
-    
-    //root group always at 0,0
-    m_root = new wxCanvasObjectGroup();
-    m_root->DeleteContents( TRUE );
-    m_root->SetOwner(this);
+    m_scrolled=FALSE;
+    m_root=0;
+    m_yaxis=FALSE;
 }
 
 wxCanvas::~wxCanvas()
@@ -1202,22 +1922,18 @@ wxCanvas::~wxCanvas()
     }
 }
 
-void wxCanvas::SetArea( int width, int height )
-{
-    SetScrollbars( 10, 10, width/10, height/10 );
-}
-
-void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char blue )
+void wxCanvas::SetColour( const wxColour& background )
 {
-    m_red = red;
-    m_green = green;
-    m_blue = blue;
-
-    SetBackgroundColour( wxColour( red, green, blue ) );
+    m_background=background;
+    SetBackgroundColour( m_background );
 
     if (m_frozen) return;
 
 #if IMAGE_CANVAS
+    unsigned char red = background.Red();
+    unsigned char green = background.Green();
+    unsigned char blue = background.Blue();
+
     unsigned char *data = m_buffer.GetData();
 
     for (int y = 0; y < m_buffer.GetHeight(); y++)
@@ -1234,7 +1950,7 @@ void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char
     wxMemoryDC dc;
     dc.SelectObject( m_buffer );
     dc.SetPen( *wxTRANSPARENT_PEN );
-    wxBrush brush( wxColour( red,green,blue), wxSOLID );
+    wxBrush brush( m_background, wxSOLID );
     dc.SetBrush( brush );
     dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
     dc.SelectObject( wxNullBitmap );
@@ -1274,39 +1990,41 @@ void wxCanvas::Thaw()
     m_frozen = FALSE;
 
     if (m_buffer.Ok())
-        Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight() );
+        Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight() );
 }
 
 void wxCanvas::Update( int x, int y, int width, int height, bool blit )
 {
-    CalcScrolledPosition( 0, 0, &m_oldDeviceX, &m_oldDeviceY );
-    
+    m_admin->SetActive(this);
+
+    if (!m_root) return;
+
     if (m_frozen) return;
 
     // clip to buffer
-    if (x < m_bufferX)
+    if (x < 0)
     {
-        width -= m_bufferX-x;
-        x = m_bufferX;
+        width -= -x;
+        x = 0;
     }
     if (width <= 0) return;
 
-    if (y < m_bufferY)
+    if (y < 0)
     {
-        height -= m_bufferY-y;
-        y = m_bufferY;
+        height -= -y;
+        y = 0;
     }
     if (height <= 0) return;
 
-    if (x+width > m_bufferX+m_buffer.GetWidth())
+    if (x+width > m_buffer.GetWidth())
     {
-        width = m_bufferX+m_buffer.GetWidth() - x;
+        width = m_buffer.GetWidth() - x;
     }
     if (width <= 0) return;
 
-    if (y+height > m_bufferY+m_buffer.GetHeight())
+    if (y+height > m_buffer.GetHeight())
     {
-        height = m_bufferY+m_buffer.GetHeight() - y;
+        height = m_buffer.GetHeight() - y;
     }
     if (height <= 0) return;
 
@@ -1320,28 +2038,51 @@ void wxCanvas::Update( int x, int y, int width, int height, bool blit )
             (wxObject*) new wxRect( x,y,width,height ) );
     }
 
+    wxTransformMatrix cworld;
+
 #if IMAGE_CANVAS
     // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
-    int start_y = y - m_bufferY;
-    int end_y = y+height - m_bufferY;
-    int start_x = x - m_bufferX;
-    int end_x = x+width - m_bufferX;
+    int start_y = y;
+    int end_y = y+height;
+    int start_x = x;
+    int end_x = x+width;
+    int red=m_background.Red();
+    int green=m_background.Green();
+    int blue=m_background.Blue();
     for (int yy = start_y; yy < end_y; yy++)
         for (int xx = start_x; xx < end_x; xx++)
-            m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue );
+            m_buffer.SetRGB( xx, yy, red, green, blue );
 
-    m_root->Render(0,0, x, y, width, height );
+    m_root->Render(&cworld, x, y, width, height );
 #else
     wxMemoryDC dc;
     dc.SelectObject( m_buffer );
+
     dc.SetPen( *wxTRANSPARENT_PEN );
-    wxBrush brush( wxColour( m_red,m_green,m_blue), wxSOLID );
+    wxBrush brush( m_background , wxSOLID );
     dc.SetBrush( brush );
-    dc.DrawRectangle( x-m_bufferX, y-m_bufferY, width, height );
 
-    m_renderDC = &dc;
-    m_root->Render(0,0, x, y, width, height );
+    if (width != m_buffer.GetWidth() && height != m_buffer.GetHeight())
+    {
+        dc.SetLogicalFunction(wxCOPY);
+        dc.SetClippingRegion(x,y,width,height);
+        dc.DrawRectangle(x-2,y-2,width+4,height+4);
+        dc.DestroyClippingRegion();
+    }
+    else
+    {
+        dc.Clear();
+        dc.SetLogicalFunction(wxCOPY);
+        dc.DrawRectangle(0,0,m_buffer.GetWidth(),m_buffer.GetHeight());
+    }
+    dc.SetBrush(wxNullBrush);
+    dc.SetPen(wxNullPen);
+
+    m_renderDC=&dc;
+
+    m_root->Render(&cworld,x, y, width, height );
 
+    m_renderDC=0;
     dc.SelectObject( wxNullBitmap );
 #endif
 }
@@ -1353,13 +2094,9 @@ void wxCanvas::BlitBuffer( wxDC &dc )
     {
         wxRect *rect = (wxRect*) node->Data();
 
-        wxRect sub_rect( *rect );
-        sub_rect.x -= m_bufferX;
-        sub_rect.y -= m_bufferY;
-
 #if IMAGE_CANVAS
 
-        wxImage sub_image( m_buffer.GetSubImage( sub_rect ) );
+        wxImage sub_image( m_buffer.GetSubImage( *rect ) );
 #ifdef __WXGTK__
         int bpp = wxDisplayDepth();
         if (bpp > 8)
@@ -1395,8 +2132,14 @@ void wxCanvas::BlitBuffer( wxDC &dc )
 
         // Maybe clipping use SetClipping() is faster than
         // getting the subrect first and drawing it then?
-        wxBitmap sub_bitmap( m_buffer.GetSubBitmap( sub_rect ) );
-        dc.DrawBitmap( sub_bitmap, rect->x, rect->y );
+
+//        wxBitmap sub_bitmap( m_buffer.GetSubBitmap( *rect ) );
+//        dc.DrawBitmap( sub_bitmap, rect->x, rect->y );
+
+        wxMemoryDC mdc;
+        mdc.SelectObject( m_buffer );
+        dc.Blit (rect->x, rect->y , rect->GetWidth(), rect->GetHeight(),&mdc, rect->x, rect->y );
+        mdc.SelectObject( wxNullBitmap );
 
 #endif
         delete rect;
@@ -1419,78 +2162,6 @@ void wxCanvas::UpdateNow()
     BlitBuffer( dc );
 }
 
-int wxCanvas::GetDeviceX( double x )
-{
-    return (int) x;
-}
-
-int wxCanvas::GetDeviceY( double y )
-{
-    return (int) y;
-}
-
-int wxCanvas::GetDeviceWidth( double width )
-{
-    return (int) width;
-}
-
-int wxCanvas::GetDeviceHeight( double height )
-{
-    return (int) height;
-}
-
-void wxCanvas::Recreate()
-{
-    m_root->Recreate();
-}
-
-void wxCanvas::Prepend( wxCanvasObject* obj )
-{
-    m_root->Prepend( obj );
-    obj->SetOwner(this);
-
-    m_root->Recreate();
-
-    if (!obj->IsControl())
-        Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
-}
-
-void wxCanvas::Append( wxCanvasObject* obj )
-{
-    m_root->Append( obj );
-    obj->SetOwner(this);
-
-    m_root->Recreate();
-
-    if (!obj->IsControl())
-        Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
-}
-
-void wxCanvas::Insert( size_t before, wxCanvasObject* obj )
-{
-    m_root->Insert( before, obj );
-    obj->SetOwner(this);
-
-    m_root->Recreate();
-
-    if (!obj->IsControl())
-        Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
-}
-
-void wxCanvas::Remove( wxCanvasObject* obj )
-{
-    int x = obj->GetX();
-    int y = obj->GetY();
-    int w = obj->GetWidth();
-    int h = obj->GetHeight();
-    bool ic = obj->IsControl();
-
-    m_root->Remove( obj );
-
-    if (!ic)
-        Update( x, y, w, h );
-}
-
 void wxCanvas::OnPaint(wxPaintEvent &event)
 {
     wxPaintDC dc(this);
@@ -1518,7 +2189,6 @@ void wxCanvas::OnPaint(wxPaintEvent &event)
 
         if ((w > 0) && (h > 0))
         {
-            CalcUnscrolledPosition( x, y, &x, &y );
             m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
         }
 
@@ -1532,14 +2202,26 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
 {
     // If any updates are pending, do them now since they will
     // expect the previous m_bufferX and m_bufferY as well as
-    // the previous device origin values. 
+    // the previous device origin values.
     wxClientDC dc( this );
     dc.SetDeviceOrigin( m_oldDeviceX, m_oldDeviceY );
     BlitBuffer( dc );
 
-    // The buffer always starts at the top left corner of the
-    // client area. Indeed, it is the client area.
-    CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
+    if (dy != 0)
+    {
+        double dyv=DeviceToLogicalYRel(dy);
+        m_virt_minY=m_virt_minY-dyv;
+        m_virt_maxY=m_virt_maxY-dyv;
+    }
+    if (dx != 0)
+    {
+        double dxv=DeviceToLogicalXRel(dx);
+        m_virt_minX=m_virt_minX-dxv;
+        m_virt_maxX=m_virt_maxX-dxv;
+    }
+
+    m_admin->SetActive(this);
+    SetMappingScroll(m_virt_minX,m_virt_minY,m_virt_maxX,m_virt_maxY,FALSE);
 
 #if IMAGE_CANVAS
     unsigned char* data = m_buffer.GetData();
@@ -1556,7 +2238,7 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
             // We update the new buffer area, but there is no need to
             // blit (last param FALSE) since the ensuing paint event will
             // do that anyway.
-            Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), dy, FALSE );
+            Update( 0, 0, m_buffer.GetWidth(), dy, FALSE );
         }
         else
         {
@@ -1568,7 +2250,7 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
             // We update the new buffer area, but there is no need to
             // blit (last param FALSE) since the ensuing paint event will
             // do that anyway.
-            Update( m_bufferX, m_bufferY+m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE );
+            Update( 0, m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE );
         }
     }
 
@@ -1587,7 +2269,7 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
             // We update the new buffer area, but there is no need to
             // blit (last param FALSE) since the ensuing paint event will
             // do that anyway.
-            Update( m_bufferX, m_bufferY, dx, m_buffer.GetHeight(), FALSE );
+            Update( 0,0, dx, m_buffer.GetHeight(), FALSE );
         }
         else
         {
@@ -1602,22 +2284,92 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
             // We update the new buffer area, but there is no need to
             // blit (last param FALSE) since the ensuing paint event will
             // do that anyway.
-            Update( m_bufferX+m_buffer.GetWidth()+dx, m_bufferY, -dx, m_buffer.GetHeight(), FALSE );
+            Update( m_buffer.GetWidth()+dx, 0, -dx, m_buffer.GetHeight(), FALSE );
         }
     }
 #else
-    // Update everything, TODO: scrolling
-    Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
-#endif
 
+    if (dy != 0)
+    {
+        if (dy > 0 && dy < m_buffer.GetHeight())
+        {
+            wxRect rect( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight()-dy);
+            wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
+            wxMemoryDC dcm;
+            dcm.SelectObject( m_buffer );
+            dcm.DrawBitmap( sub_bitmap, 0, dy, TRUE );
+            dcm.SelectObject( wxNullBitmap );
+
+            Update( 0, 0, m_buffer.GetWidth(), dy, TRUE );
+        }
+        else  if (dy < 0 && dy > -m_buffer.GetHeight())
+        {
+            wxRect rect( 0, -dy, m_buffer.GetWidth(), m_buffer.GetHeight()+dy);
+            wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
+            wxMemoryDC dcm;
+            dcm.SelectObject( m_buffer );
+            dcm.DrawBitmap( sub_bitmap, 0, 0, TRUE );
+            dcm.SelectObject( wxNullBitmap );
+
+            Update( 0, m_buffer.GetHeight()+dy, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
+        }
+        else
+            Update( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
+    }
+
+    if (dx != 0)
+    {
+        if (dx > 0 && dx < m_buffer.GetWidth())
+        {
+            wxRect rect( 0, 0, m_buffer.GetWidth()-dx, m_buffer.GetHeight());
+            wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
+            wxMemoryDC dcm;
+            dcm.SelectObject( m_buffer );
+            dcm.DrawBitmap( sub_bitmap, dx, 0, TRUE );
+            dcm.SelectObject( wxNullBitmap );
+
+            Update( 0, 0, dx, m_buffer.GetHeight(), TRUE );
+        }
+        else if (dx < 0 && dx > -m_buffer.GetWidth())
+        {
+            wxRect rect( -dx, 0, m_buffer.GetWidth()+dx, m_buffer.GetHeight());
+            wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
+            wxMemoryDC dcm;
+            dcm.SelectObject( m_buffer );
+            dcm.DrawBitmap( sub_bitmap, 0, 0, TRUE );
+            dcm.SelectObject( wxNullBitmap );
+
+            Update( m_buffer.GetWidth()+dx, 0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
+        }
+        else
+            Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
+    }
+#endif
     wxWindow::ScrollWindow( dx, dy, rect );
+
+    //must be done now because quick repeated scrolling will prevent wxPaint
+    //from doing it properly
+    UpdateNow();
 }
 
 void wxCanvas::OnMouse(wxMouseEvent &event)
 {
+    m_admin->SetActive(this);
+    if (!m_root)
+    {
+        event.Skip();
+        return;
+    }
+
     int x = event.GetX();
     int y = event.GetY();
-    CalcUnscrolledPosition( x, y, &x, &y );
+
+    //to world coordinates to do hit test in world coordinates
+    double xw = DeviceToLogicalX( x );
+    double yw = DeviceToLogicalY( y );
+
+    //make a select margin of 2 pixels, so also zero line thickness will be hit
+    double margin = DeviceToLogicalXRel( 2 );
 
     if (event.GetEventType() == wxEVT_MOTION)
     {
@@ -1625,8 +2377,8 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
         {
             wxMouseEvent child_event( wxEVT_MOTION );
             child_event.SetEventObject(m_captureMouse);
-            child_event.m_x = x - m_captureMouse->GetX();
-            child_event.m_y = y - m_captureMouse->GetY();
+            child_event.m_x = x;
+            child_event.m_y = y;
             child_event.m_leftDown = event.m_leftDown;
             child_event.m_rightDown = event.m_rightDown;
             child_event.m_middleDown = event.m_middleDown;
@@ -1634,20 +2386,20 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
             child_event.m_shiftDown = event.m_shiftDown;
             child_event.m_altDown = event.m_altDown;
             child_event.m_metaDown = event.m_metaDown;
-            
-            m_captureMouse->ProcessEvent( child_event );
+
+            m_captureMouse->ProcessCanvasObjectEvent( child_event );
             return;
         }
         else
         {
-            wxCanvasObject *obj = m_root->IsHitObject(x,y,0);
+            wxCanvasObject *obj = m_root->IsHitWorld(xw,yw,margin);
 
             if (obj && !obj->IsControl())
             {
                 wxMouseEvent child_event( wxEVT_MOTION );
                 child_event.SetEventObject( obj );
-                child_event.m_x = x - obj->GetX();
-                child_event.m_y = y - obj->GetY();
+                child_event.m_x = x;
+                child_event.m_y = y;
                 child_event.m_leftDown = event.m_leftDown;
                 child_event.m_rightDown = event.m_rightDown;
                 child_event.m_middleDown = event.m_middleDown;
@@ -1660,22 +2412,22 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
                 {
                     child_event.SetEventType( wxEVT_LEAVE_WINDOW );
                     child_event.SetEventObject( m_lastMouse );
-                    child_event.m_x = x - m_lastMouse->GetX();
-                    child_event.m_y = y - m_lastMouse->GetY();
-                    m_lastMouse->ProcessEvent( child_event );
+                    child_event.m_x = x;
+                    child_event.m_y = y;
+                    m_lastMouse->ProcessCanvasObjectEvent( child_event );
 
                     m_lastMouse = obj;
                     child_event.SetEventType( wxEVT_ENTER_WINDOW );
                     child_event.SetEventObject( m_lastMouse );
-                    child_event.m_x = x - m_lastMouse->GetX();
-                    child_event.m_y = y - m_lastMouse->GetY();
-                    m_lastMouse->ProcessEvent( child_event );
+                    child_event.m_x = x;
+                    child_event.m_y = y;
+                    m_lastMouse->ProcessCanvasObjectEvent( child_event );
 
                     child_event.SetEventType( wxEVT_MOTION );
                     child_event.SetEventObject( obj );
                 }
-                
-                obj->ProcessEvent( child_event );
+
+                obj->ProcessCanvasObjectEvent( child_event );
                 return;
             }
         }
@@ -1683,8 +2435,8 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
         {
             wxMouseEvent child_event( wxEVT_LEAVE_WINDOW );
             child_event.SetEventObject( m_lastMouse );
-            child_event.m_x = x - m_lastMouse->GetX();
-            child_event.m_y = y - m_lastMouse->GetY();
+            child_event.m_x = x;
+            child_event.m_y = y;
             child_event.m_leftDown = event.m_leftDown;
             child_event.m_rightDown = event.m_rightDown;
             child_event.m_middleDown = event.m_middleDown;
@@ -1692,7 +2444,7 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
             child_event.m_shiftDown = event.m_shiftDown;
             child_event.m_altDown = event.m_altDown;
             child_event.m_metaDown = event.m_metaDown;
-            m_lastMouse->ProcessEvent( child_event );
+            m_lastMouse->ProcessCanvasObjectEvent( child_event );
 
             m_lastMouse = (wxCanvasObject*) NULL;
             return;
@@ -1704,8 +2456,8 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
         {
             wxMouseEvent child_event( event.GetEventType() );
             child_event.SetEventObject(m_captureMouse);
-            child_event.m_x = x - m_captureMouse->GetX();
-            child_event.m_y = y - m_captureMouse->GetY();
+            child_event.m_x = x;
+            child_event.m_y = y;
             child_event.m_leftDown = event.m_leftDown;
             child_event.m_rightDown = event.m_rightDown;
             child_event.m_middleDown = event.m_middleDown;
@@ -1713,18 +2465,18 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
             child_event.m_shiftDown = event.m_shiftDown;
             child_event.m_altDown = event.m_altDown;
             child_event.m_metaDown = event.m_metaDown;
-            m_captureMouse->ProcessEvent( child_event );
+            m_captureMouse->ProcessCanvasObjectEvent( child_event );
         }
         else
         {
-            wxCanvasObject *obj = m_root->IsHitObject(x,y,0);
+            wxCanvasObject *obj = m_root->IsHitWorld(xw,yw,margin);
 
             if (obj && !obj->IsControl())
             {
                 wxMouseEvent child_event( event.GetEventType() );
                 child_event.SetEventObject( obj );
-                child_event.m_x = x - obj->GetX();
-                child_event.m_y = y - obj->GetY();
+                child_event.m_x = x;
+                child_event.m_y = y;
                 child_event.m_leftDown = event.m_leftDown;
                 child_event.m_rightDown = event.m_rightDown;
                 child_event.m_middleDown = event.m_middleDown;
@@ -1732,8 +2484,8 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
                 child_event.m_shiftDown = event.m_shiftDown;
                 child_event.m_altDown = event.m_altDown;
                 child_event.m_metaDown = event.m_metaDown;
-                
-                obj->ProcessEvent( child_event );
+
+                obj->ProcessCanvasObjectEvent( child_event );
                 return;
             }
         }
@@ -1745,14 +2497,22 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
 void wxCanvas::OnSize(wxSizeEvent &event)
 {
     int w,h;
+
     GetClientSize( &w, &h );
+
 #if IMAGE_CANVAS
     m_buffer = wxImage( w, h );
 #else
+    wxMemoryDC dc;
     m_buffer = wxBitmap( w, h );
-#endif
+    dc.SelectObject( m_buffer );
+    dc.SetPen( *wxTRANSPARENT_PEN );
+    wxBrush brush( m_background , wxSOLID );
+    dc.SetBrush( brush );
+    dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
+    dc.SelectObject( wxNullBitmap );
 
-    CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
+#endif
 
     wxNode *node = m_updateRects.First();
     while (node)
@@ -1765,34 +2525,382 @@ void wxCanvas::OnSize(wxSizeEvent &event)
 
     m_frozen = FALSE;
 
-    Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
+    m_admin->SetActive(this);
+    SetMappingScroll(m_virt_minX,m_virt_minY,m_virt_maxX,m_virt_maxY,FALSE);
+
+    Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
 
     event.Skip();
 }
 
 void wxCanvas::OnIdle(wxIdleEvent &event)
 {
+    m_admin->SetActive(this);
     UpdateNow();
     event.Skip();
 }
 
 void wxCanvas::OnSetFocus(wxFocusEvent &event)
 {
+    m_admin->SetActive(this);
 }
 
 void wxCanvas::OnKillFocus(wxFocusEvent &event)
 {
 }
 
-void wxCanvas::OnChar(wxKeyEvent &event)
+
+void wxCanvas::OnEraseBackground(wxEraseEvent &event)
 {
-    event.Skip();
 }
 
-void wxCanvas::OnEraseBackground(wxEraseEvent &event)
+
+
+// maps the virtual window (Real drawing to the window coordinates
+// also used for zooming
+void wxCanvas::SetMappingScroll( double vx1,    double vy1, double vx2, double vy2, bool border)
+{
+    int dwxi,dwyi;
+    GetClientSize(&dwxi,&dwyi);
+
+    if (vx2==vx1) vx2=vx1+100000;
+    if (vy2==vy1) vy2=vy1+100000;
+    m_virt_minX=vx1;
+    m_virt_minY=vy1;
+    m_virt_maxX=vx2;
+    m_virt_maxY=vy2;
+
+    double dwx=dwxi;
+    double dwy=dwyi;
+    if (dwx==0) dwx=1;
+    if (dwy==0) dwy=1;
+
+    double dvx = m_virt_maxX - m_virt_minX;
+    double dvy = m_virt_maxY - m_virt_minY;
+
+    // calculate the scaling factor for the virtual window
+    double temp_x=0;
+    double temp_y=0;
+    if ((dvy / dvx) < (dwy / dwx))
+    {
+        dvy = dvx * (dwy / dwx);
+        // calculate the change in the coordinates
+        temp_y = (dvy - (m_virt_maxY - m_virt_minY) )/ 2.0;
+    }
+    else
+    {
+        dvx = dvy * (dwx / dwy);
+        // calculate the change in the coordinates
+        temp_x = (dvx - (m_virt_maxX - m_virt_minX) )/ 2.0;
+    }
+
+    // add or substract the change from the original coordinates
+    m_virt_minX=m_virt_minX-temp_x;
+    m_virt_minY=m_virt_minY-temp_y;
+
+    m_virt_maxX=m_virt_maxX+temp_x;
+    m_virt_maxY=m_virt_maxY+temp_y;
+
+    // initialize the mapping_matrix used for mapping the
+    // virtual windows to the drawing window
+
+     // make mappingmatrix
+    m_mapping_matrix.Identity();
+    if (!border)
+        // translate the drawing to 0,0
+        if (m_yaxis)
+            m_mapping_matrix.Translate(-m_virt_minX,-m_virt_maxY);
+        else
+            m_mapping_matrix.Translate(-m_virt_minX,-m_virt_minY);
+    else
+    {
+        // make a small white border around the drawing
+        m_virt_minX=m_virt_minX- 0.05 * dvx;
+        m_virt_minY=m_virt_minY- 0.05 * dvy;
+
+        m_virt_maxX=m_virt_maxX+ 0.05 * dvx;
+        m_virt_maxY=m_virt_maxY+ 0.05 * dvy;
+
+        // translate the drawing to 0,0
+        if (m_yaxis)
+            m_mapping_matrix.Translate(-m_virt_minX,-m_virt_maxY);
+        else
+            m_mapping_matrix.Translate(-m_virt_minX,-m_virt_minY);
+    }
+
+    double scalefactor_x = dwx;
+    scalefactor_x /= (m_virt_maxX - m_virt_minX);
+
+    double scalefactor_y = dwy;
+    scalefactor_y /= (m_virt_maxY - m_virt_minY);
+
+    // scale the drawing so it fit's in the window
+    m_mapping_matrix.Scale(scalefactor_x, scalefactor_y, 0, 0);
+
+    // because of coordinate change mirror over X
+    // 0,0 in graphic computerscreens: upperleft corner
+    // 0,0 in cartesian: lowerleft corner
+    if (m_yaxis)
+    {
+        m_mapping_matrix.Mirror();
+    }
+    // make inverse of mapping matrix
+    // this is to set coordinates in the statusbar
+    // and the calculate screencoordinates to world coordinates used
+    // in zooming
+    m_inverse_mapping=m_mapping_matrix;
+    m_inverse_mapping.Invert();
+
+    if (m_scrolled)
+        SetScroll(m_virtm_minX,m_virtm_minY,m_virtm_maxX,m_virtm_maxY);
+
+    int dx2,dy2;
+    GetClientSize(&dx2,&dy2);
+    if ( dwxi != dx2 || dwyi  != dy2) //scrollbar is/became empty
+        SetScroll(m_virtm_minX,m_virtm_minY,m_virtm_maxX,m_virtm_maxY);
+}
+
+
+void wxCanvas::SetScroll(double vx1,double vy1,double vx2,double vy2)
+{
+    m_virtm_minX=vx1;
+    m_virtm_minY=vy1;
+    m_virtm_maxX=vx2;
+    m_virtm_maxY=vy2;
+
+    double dvx = m_virt_maxX - m_virt_minX;
+    double dvy = m_virt_maxY - m_virt_minY;
+    double dmvx = m_virtm_maxX - m_virtm_minX;
+    double dmvy = m_virtm_maxY - m_virtm_minY;
+
+    SetScrollbar(wxHORIZONTAL,(m_virt_minX-m_virtm_minX)/dmvx *1000,dvx/dmvx *1000,1000,true);
+    if (m_yaxis)
+    {
+        SetScrollbar(wxVERTICAL,(m_virtm_maxY-m_virt_maxY)/dmvy *1000,dvy/dmvy *1000,1000,true);
+    }
+    else
+    {
+        SetScrollbar(wxVERTICAL,(m_virt_minY-m_virtm_minY)/dmvy *1000,dvy/dmvy *1000,1000,true);
+    }
+
+    m_scrolled=true;
+}
+
+// coordinates conversions
+// -----------------------
+double wxCanvas::DeviceToLogicalX(int x) const
 {
+    return m_inverse_mapping.GetValue(0,0) * x + m_inverse_mapping.GetValue(2,0);
 }
 
+double wxCanvas::DeviceToLogicalY(int y) const
+{
+    return m_inverse_mapping.GetValue(1,1) * y + m_inverse_mapping.GetValue(2,1);
+}
+
+double wxCanvas::DeviceToLogicalXRel(int x) const
+{
+    return x*m_inverse_mapping.GetValue(0,0);
+}
+
+double wxCanvas::DeviceToLogicalYRel(int y) const
+{
+    return y*m_inverse_mapping.GetValue(1,1);
+}
+
+int wxCanvas::LogicalToDeviceX(double x) const
+{
+    return (int) (m_mapping_matrix.GetValue(0,0) * x + m_mapping_matrix.GetValue(2,0) + 0.5);
+}
+
+int wxCanvas::LogicalToDeviceY(double y) const
+{
+    return (int) (m_mapping_matrix.GetValue(1,1) * y + m_mapping_matrix.GetValue(2,1) + 0.5);
+}
+
+int wxCanvas::LogicalToDeviceXRel(double x) const
+{
+    return (int) (x*m_mapping_matrix.GetValue(0,0) + 0.5);
+}
+
+int wxCanvas::LogicalToDeviceYRel(double y) const
+{
+    return (int) (y*m_mapping_matrix.GetValue(1,1) + 0.5);
+}
+
+
+
+// return the inverse mapping matrix for zooming or coordinates
+wxTransformMatrix wxCanvas::GetInverseMappingMatrix()
+{
+    return m_inverse_mapping;
+}
+
+wxTransformMatrix wxCanvas::GetMappingMatrix()
+{
+    return m_mapping_matrix;
+}
+
+
+// ----------------------------------------------------------------------------
+// scrolling behaviour
+// ----------------------------------------------------------------------------
+
+void wxCanvas::OnScroll(wxScrollWinEvent& event)
+{
+    if (event.GetEventType()==wxEVT_SCROLLWIN_THUMBRELEASE)
+    {
+        if (event.GetOrientation()==wxHORIZONTAL)
+        {
+          double x=m_virtm_minX+event.GetPosition()/1000.0*(m_virtm_maxX-m_virtm_minX);
+          x=LogicalToDeviceXRel(x-m_virt_minX);
+          ScrollWindow(-x, 0, (const wxRect *) NULL);
+        }
+        else
+        {
+          double y=m_virtm_minY+event.GetPosition()/1000.0*(m_virtm_maxY-m_virtm_minY);
+          y=LogicalToDeviceYRel(y-m_virt_minY);
+          ScrollWindow(0, -y, (const wxRect *) NULL);
+        }
+    }
+    else if (event.GetEventType()==wxEVT_SCROLLWIN_PAGEUP)
+    {
+        if (event.GetOrientation()==wxHORIZONTAL)
+        {
+          double x=GetBufferWidth();
+          ScrollWindow(x, 0, (const wxRect *) NULL);
+        }
+        else
+        {
+          double y=GetBufferHeight();
+          ScrollWindow(0, y, (const wxRect *) NULL);
+        }
+    }
+    else if (event.GetEventType()==wxEVT_SCROLLWIN_PAGEDOWN)
+    {
+        if (event.GetOrientation()==wxHORIZONTAL)
+        {
+          double x=-GetBufferWidth();
+          ScrollWindow(x, 0, (const wxRect *) NULL);
+        }
+        else
+        {
+          double y=-GetBufferHeight();
+          ScrollWindow(0, y, (const wxRect *) NULL);
+        }
+    }
+    else if (event.GetEventType()==wxEVT_SCROLLWIN_LINEUP)
+    {
+        if (event.GetOrientation()==wxHORIZONTAL)
+        {
+          int x=GetBufferWidth()/10;
+          ScrollWindow(x, 0, (const wxRect *) NULL);
+        }
+        else
+        {
+          int y=GetBufferHeight()/10;
+          ScrollWindow(0, y, (const wxRect *) NULL);
+        }
+    }
+    else if (event.GetEventType()==wxEVT_SCROLLWIN_LINEDOWN)
+    {
+        if (event.GetOrientation()==wxHORIZONTAL)
+        {
+          int x=-GetBufferWidth()/10;
+          ScrollWindow(x, 0, (const wxRect *) NULL);
+        }
+        else
+        {
+          int y=-GetBufferHeight()/10;
+          ScrollWindow(0, y, (const wxRect *) NULL);
+        }
+    }
+
+}
+
+void wxCanvas::OnChar(wxKeyEvent& event)
+{
+    switch ( event.KeyCode() )
+    {
+        case WXK_PAGEUP:
+        case WXK_PRIOR:
+            {
+              double y=GetBufferHeight();
+              ScrollWindow(0, y, (const wxRect *) NULL);
+            }
+            break;
+        case WXK_PAGEDOWN:
+        case WXK_NEXT:
+            {
+              double y=-GetBufferHeight();
+              ScrollWindow(0, y, (const wxRect *) NULL);
+            }
+            break;
+        case WXK_HOME:
+            {
+                double y=m_virtm_minY;
+                y=LogicalToDeviceYRel(y-m_virt_minY);
+                ScrollWindow(0, -y, (const wxRect *) NULL);
+            }
+            break;
+        case WXK_END:
+            {
+                double y=m_virtm_minY+(m_virtm_maxY-m_virtm_minY);
+                y=LogicalToDeviceYRel(y-m_virt_minY);
+                ScrollWindow(0, -y, (const wxRect *) NULL);
+            }
+            break;
+        case WXK_UP:
+            {
+                int y;
+                if  (!event.ControlDown())
+                    y=GetBufferHeight()/10;
+                else
+                    y=GetBufferHeight();
+                ScrollWindow(0, y, (const wxRect *) NULL);
+            }
+            break;
+
+        case WXK_DOWN:
+            {
+                int y;
+                if  (!event.ControlDown())
+                    y=-GetBufferHeight()/10;
+                else
+                    y=-GetBufferHeight();
+                ScrollWindow(0, y, (const wxRect *) NULL);
+            }
+            break;
+
+        case WXK_LEFT:
+            {
+                int x;
+                if  (!event.ControlDown())
+                    x=GetBufferWidth()/10;
+                else
+                    x=GetBufferWidth();
+                ScrollWindow(x, 0, (const wxRect *) NULL);
+            }
+            break;
+        case WXK_RIGHT:
+            {
+                int x;
+                if  (!event.ControlDown())
+                    x=-GetBufferWidth()/10;
+                else
+                    x=-GetBufferWidth();
+                ScrollWindow(x, 0, (const wxRect *) NULL);
+            }
+            break;
+        default:
+            // not for us
+            event.Skip();
+    }
+}
+
+
+
+
 //--------------------------------------------------------------------
 // wxCanvasModule
 //--------------------------------------------------------------------
@@ -1825,3 +2933,143 @@ void wxCanvasModule::OnExit()
     FT_Done_FreeType( g_freetypeLibrary );
 #endif
 }
+
+
+wxCanvasAdmin::wxCanvasAdmin()
+{
+
+}
+
+wxCanvasAdmin::~wxCanvasAdmin()
+{
+
+
+}
+
+
+void wxCanvasAdmin::Append( wxCanvas* canvas )
+{
+    m_canvaslist.Append( canvas );
+}
+
+void wxCanvasAdmin::Remove( wxCanvas* canvas )
+{
+    m_canvaslist.DeleteObject( canvas );
+}
+
+void wxCanvasAdmin::Update(wxCanvasObject* obj, double x, double y, double width, double height)
+{
+    wxNode *node = m_canvaslist.First();
+    while (node)
+    {
+
+        wxCanvas *canvas = (wxCanvas*) node->Data();
+
+        if (m_active == canvas)
+        {
+            int xi = canvas->LogicalToDeviceX( x);
+            int yi = canvas->LogicalToDeviceY( y);
+            int wi = canvas->LogicalToDeviceXRel( width );
+            int hi = canvas->LogicalToDeviceYRel( height);
+            //update a little more then is strictly needed,
+            //to get rid of the 1 bit bugs
+            if (canvas->GetYaxis())
+                canvas->Update( xi-2, yi+hi-2, wi+4, -hi+4);
+            else
+                canvas->Update( xi-2, yi-2, wi+4, hi+4);
+        }
+        else
+        {   wxCanvasObject* topobj=canvas->GetRoot()->Contains(obj);
+            if (topobj)
+            {
+                wxCanvas* tcanvas = m_active;
+                SetActive(canvas);
+
+                /*
+                //KKK TODO somehow the next does not work for update i do not know why
+                canvas->GetRoot()->CalcBoundingBox();
+                int xi = topobj->GetX();
+                int yi = topobj->GetY();
+                int wi = topobj->GetWidth();
+                int hi = topobj->GetHeight();
+                */
+                canvas->Update( 0,0, canvas->GetBufferWidth(),canvas->GetBufferHeight());
+                SetActive(tcanvas);
+            }
+        }
+
+        node = node->Next();
+    }
+}
+
+void wxCanvasAdmin::UpdateNow()
+{
+    wxNode *node = m_canvaslist.First();
+    while (node)
+    {
+        wxCanvas *canvas = (wxCanvas*) node->Data();
+
+        canvas->UpdateNow();
+        node = node->Next();
+    }
+}
+
+// coordinates conversions
+// -----------------------
+double wxCanvasAdmin::DeviceToLogicalX(int x) const
+{
+    return m_active->DeviceToLogicalX(x);
+}
+
+double wxCanvasAdmin::DeviceToLogicalY(int y) const
+{
+    return m_active->DeviceToLogicalY(y);
+}
+
+double wxCanvasAdmin::DeviceToLogicalXRel(int x) const
+{
+    return m_active->DeviceToLogicalXRel(x);
+}
+
+double wxCanvasAdmin::DeviceToLogicalYRel(int y) const
+{
+    return m_active->DeviceToLogicalYRel(y);
+}
+
+int wxCanvasAdmin::LogicalToDeviceX(double x) const
+{
+    return m_active->LogicalToDeviceX(x);
+}
+
+int wxCanvasAdmin::LogicalToDeviceY(double y) const
+{
+    return m_active->LogicalToDeviceY(y);
+}
+
+int wxCanvasAdmin::LogicalToDeviceXRel(double x) const
+{
+    return m_active->LogicalToDeviceXRel(x);
+}
+
+int wxCanvasAdmin::LogicalToDeviceYRel(double y) const
+{
+    return m_active->LogicalToDeviceYRel(y);
+}
+
+void wxCanvasAdmin::SetActive(wxCanvas* activate)
+{
+    wxNode *node = m_canvaslist.First();
+    while (node)
+    {
+        wxCanvas *canvas = (wxCanvas*) node->Data();
+
+        if (activate == canvas)
+        {
+            m_active=canvas;
+            break;
+        }
+        node = node->Next();
+    }
+}
+
+
diff --git a/contrib/src/canvas/liner.cpp b/contrib/src/canvas/liner.cpp
new file mode 100644 (file)
index 0000000..02ca170
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+Program wxLine.CPP
+Purpose Mainly used for calculating crossings
+Last Update 05-12-1995
+*/
+
+#ifdef __GNUG__
+#pragma implementation "liner.cpp"
+#endif
+
+#include <math.h>
+
+#include <stdlib.h>
+
+#include "liner.h"
+
+wxLine::wxLine( double x1, double y1, double x2, double y2 )
+{
+    m_AA = 0.0;
+    m_BB = 0.0;
+    m_CC = 0.0;
+
+    m_a=wxPoint2DDouble(x1,y1);
+    m_b=wxPoint2DDouble(x2,y2);
+    if (m_a==m_b)
+        assert(0);
+
+    m_valid_parameters = FALSE;
+}
+
+wxLine::~wxLine()
+{
+}
+
+wxLine::wxLine(const wxPoint2DDouble& a,const wxPoint2DDouble& b)
+{
+    if (a==b)
+        assert(0);
+
+    m_a=a;
+    m_b=b;
+    m_valid_parameters = FALSE;
+}
+
+
+
+// ActionOnTable1
+// This function decide which action must be taken, after PointInLine
+// has given the results of two points in relation to a wxLine. See table 1 in the report
+//
+// input Result_beginPoint:
+//          Result_endPoint :
+//       The results can be R_R_LEFT_SIDE, R_R_RIGHT_SIDE, R_R_ON_AREA, R_R_IN_AREA
+//
+// return -1: Illegal combination
+//         0: No action, no crosspoints
+//         1: Investigate results points in relation to the other wxLine
+//         2: endPoint is a crosspoint, no further investigation
+//         3: beginPoint is a crosspoint, no further investigation
+//            4: beginPoint and endPoint are crosspoints, no further investigation
+//         5: beginPoint is a crosspoint, need further investigation
+//         6: endPoint is a crosspoint, need further investigation
+int wxLine::ActionOnTable1(R_PointStatus Result_beginPoint, R_PointStatus Result_endPoint)
+{
+    // beginPoint and endPoint are crosspoints
+    if (
+         (Result_beginPoint == R_IN_AREA)
+         &&
+         (Result_endPoint == R_IN_AREA)
+        )
+        return 4;
+   // there are no crosspoints, no action
+    if (
+         (
+          (Result_beginPoint == R_LEFT_SIDE)
+          &&
+          (Result_endPoint == R_LEFT_SIDE)
+         )
+         ||
+         (
+          (Result_beginPoint == R_RIGHT_SIDE)
+          &&
+          (Result_endPoint == R_RIGHT_SIDE)
+         )
+        )
+        return 0;
+    // maybe there is a crosspoint, further investigation needed
+    if (
+         (
+          (Result_beginPoint == R_LEFT_SIDE)
+          &&
+          (
+            (Result_endPoint == R_RIGHT_SIDE)
+            ||
+            (Result_endPoint == R_ON_AREA)
+          )
+         )
+         ||
+         (
+          (Result_beginPoint == R_RIGHT_SIDE)
+          &&
+          (
+            (Result_endPoint == R_LEFT_SIDE)
+            ||
+            (Result_endPoint == R_ON_AREA)
+          )
+         )
+         ||
+         (
+          (Result_beginPoint == R_ON_AREA)
+          &&
+          (
+            (Result_endPoint == R_LEFT_SIDE)
+            ||
+            (Result_endPoint == R_RIGHT_SIDE)
+            ||
+            (Result_endPoint == R_ON_AREA)
+          )
+         )
+        )
+        return 1;
+    //there is a crosspoint
+    if (
+         (
+          (Result_beginPoint == R_LEFT_SIDE)
+          ||
+          (Result_beginPoint == R_RIGHT_SIDE)
+         )
+         &&
+         (Result_endPoint == R_IN_AREA)
+        )
+        return 2;
+    // there is a crosspoint
+    if (
+         (Result_beginPoint == R_IN_AREA)
+         &&
+         (
+          (Result_endPoint == R_LEFT_SIDE)
+          ||
+          (Result_endPoint == R_RIGHT_SIDE)
+         )
+        )
+        return 3;
+    // beginPoint is a crosspoint, further investigation needed
+    if (
+         (Result_beginPoint == R_IN_AREA)
+         &&
+         (Result_endPoint == R_ON_AREA)
+        )
+        return 5;
+    // endPoint is a crosspoint, further investigation needed
+    if (
+         (Result_beginPoint == R_ON_AREA)
+         &&
+         (Result_endPoint == R_IN_AREA)
+        )
+        return 6;
+    // All other combinations are illegal
+    return -1;
+}
+
+
+// ActionOnTable2
+// This function decide which action must be taken, after PointInLine
+// has given the results of two points in relation to a wxLine. It can only give a
+// correct decision if first the relation of the points from the wxLine
+// are investigated in relation to the wxLine wich can be constucted from the points.
+//
+// input Result_beginPoint:
+//          Result_endPoint :
+//       The results can be R_LEFT_SIDE, R_RIGHT_SIDE, R_ON_AREA, R_IN_AREA
+//
+// return -1: Illegal combination
+//         0: No action, no crosspoints
+//         1: Calculate crosspoint
+//         2: endPoint is a crosspoint
+//         3: beginPoint is a crosspoint
+//         4: beginPoint and endPoint are crosspoints
+int wxLine::ActionOnTable2(R_PointStatus Result_beginPoint, R_PointStatus Result_endPoint)
+{
+    // beginPoint and eindpoint are crosspoints
+    if (
+         (Result_beginPoint == R_IN_AREA)
+         &&
+         (Result_endPoint == R_IN_AREA)
+        )
+        return 4;
+    // there are no crosspoints
+    if (
+         (
+          (Result_beginPoint == R_LEFT_SIDE)
+          &&
+          (
+            (Result_endPoint == R_LEFT_SIDE)
+            ||
+            (Result_endPoint == R_ON_AREA)
+          )
+         )
+         ||
+         (
+          (Result_beginPoint == R_RIGHT_SIDE)
+          &&
+          (
+            (Result_endPoint == R_RIGHT_SIDE)
+            ||
+            (Result_endPoint == R_ON_AREA)
+          )
+         )
+         ||
+         (
+          (Result_beginPoint == R_ON_AREA)
+          &&
+          (
+            (Result_endPoint == R_LEFT_SIDE)
+            ||
+            (Result_endPoint == R_RIGHT_SIDE)
+            ||
+            (Result_endPoint == R_ON_AREA)
+          )
+         )
+        )
+        return 0;
+    // there is a real intersection, which must be calculated
+    if (
+         (
+          (Result_beginPoint == R_LEFT_SIDE)
+          &&
+          (Result_endPoint == R_RIGHT_SIDE)
+         )
+         ||
+         (
+          (Result_beginPoint == R_RIGHT_SIDE)
+          &&
+          (Result_endPoint == R_LEFT_SIDE)
+         )
+        )
+        return 1;
+    // endPoint is a crosspoint
+    if (
+         (
+          (Result_beginPoint == R_LEFT_SIDE)
+          ||
+          (Result_beginPoint == R_RIGHT_SIDE)
+          ||
+          (Result_beginPoint == R_ON_AREA)
+         )
+         &&
+         (Result_endPoint == R_IN_AREA)
+        )
+        return 2;
+    // beginPoint is a crosspoint
+    if (
+         (Result_beginPoint == R_IN_AREA)
+         &&
+         (
+          (Result_endPoint == R_LEFT_SIDE)
+          ||
+          (Result_endPoint == R_RIGHT_SIDE)
+          ||
+          (Result_endPoint == R_ON_AREA)
+         )
+        )
+        return 3;
+    // All other combinations are illegal
+    return -1;
+}
+
+// Calculate the Y when the X is given
+double wxLine::Calculate_Y(double X)
+{
+    CalculateLineParameters();
+    if (m_AA != 0)
+        return -(m_AA * X + m_CC) / m_BB;
+    else
+        // horizontal wxLine
+        return m_a.m_y;
+}
+
+void wxLine::Virtual_Point(wxPoint2DDouble& a_point,double distance)  const
+{
+    assert(m_valid_parameters);
+
+    //calculate the distance using the slope of the wxLine
+   //and rotate 90 degrees
+
+    a_point.m_y=a_point.m_y + (distance * -m_BB);
+    a_point.m_x=a_point.m_x - (distance * m_AA );
+}
+
+
+
+//
+// Calculate the lineparameters for the wxLine if nessecary
+//
+void wxLine::CalculateLineParameters()
+{
+    // if not valid_parameters calculate the parameters
+    if (!m_valid_parameters)
+    {
+        double length;
+
+        // bp AND ep may not be the same
+        if (m_a == m_b)
+            assert (0);
+
+        m_AA = (m_b.m_y - m_a.m_y); // A = (Y2-Y1)
+        m_BB = (m_a.m_x - m_b.m_x); // B = (X1-X2)
+
+        // the parameters A end B can now be normalized
+        length = sqrt(m_AA*m_AA + m_BB*m_BB);
+
+        assert(length !=0);
+
+        m_AA = (m_AA / length);
+        m_BB = (m_BB / length);
+
+        m_CC = -((m_AA * m_a.m_x) + (m_a.m_y * m_BB));
+
+        m_valid_parameters = TRUE;
+    }
+}
+
+
+// Checks if a wxLine intersect with another wxLine
+// inout    wxLine : another wxLine
+//          Marge: optional, standard on MARGE (declared in MISC.CPP)
+//
+// return   true : wxLines are crossing
+//          false: wxLines are not crossing
+//
+bool wxLine::CheckIntersect (wxLine& lijn, double Marge)
+{
+    double distance=0;
+
+   // bp AND ep may not be the same
+   if (m_a == m_b)
+      assert (0);
+
+    int Take_Action1, Take_Action2;
+    bool Total_Result=FALSE;
+    R_PointStatus Result_beginPoint,Result_endPoint;
+
+    Result_beginPoint = PointInLine(lijn.m_a,distance,Marge);
+    Result_endPoint   = PointInLine(lijn.m_b,distance,Marge);
+    Take_Action1 = ActionOnTable1(Result_beginPoint,Result_endPoint);
+    switch (Take_Action1)
+    {
+        case 0: Total_Result = FALSE ; break;
+        case 1: {
+                        Result_beginPoint = lijn.PointInLine(m_a,distance,Marge);
+                        Result_endPoint   = lijn.PointInLine(m_b,distance,Marge);
+                        Take_Action2 = ActionOnTable2(Result_beginPoint,Result_endPoint);
+                        switch (Take_Action2)
+                        {
+                            case 0: Total_Result = FALSE; break;
+                            case 1: case 2: case 3: case 4: Total_Result = TRUE; break;
+                        }
+                  }; break; // This break belongs to the switch(Take_Action1)
+        case 2: case 3: case 4: case 5: case 6: Total_Result = TRUE; break;
+    }
+    return Total_Result; //This is the final decision
+}
+
+
+//
+// Get the beginPoint from the wxLine
+// usage: Point aPoint = a_line.GetBeginPoint()
+//
+wxPoint2DDouble wxLine::GetBeginPoint()
+{
+  return m_a;
+}
+
+
+//
+// Get the endPoint from the wxLine
+// usage: Point aPoint = a_line.GetEndPoint()
+//
+wxPoint2DDouble wxLine::GetEndPoint()
+{
+    return m_b;
+}
+
+// Intersects two wxLines
+// input    wxLine : another wxLine
+//          Marge: optional, standard on MARGE
+//
+// return   0: If there are no crossings
+//          1: If there is one crossing
+//          2: If there are two crossings
+int wxLine::Intersect(wxLine& lijn, wxPoint2DDouble& c1 ,wxPoint2DDouble& c2 , double Marge)
+{
+    double distance=0;
+
+    // bp AND ep may not be the same
+    if (m_a == m_b)
+        assert (0);
+
+    R_PointStatus Result_beginPoint,Result_endPoint;
+    int Take_Action1, Take_Action2, Number_of_Crossings = 0;
+
+    Result_beginPoint = PointInLine(lijn.m_a,distance,Marge);
+    Result_endPoint   = PointInLine(lijn.m_b,distance,Marge);
+
+    Take_Action1 = ActionOnTable1(Result_beginPoint,Result_endPoint);
+// 0: No action, no crosspoints
+// 1: Investigate results points in relation to the other wxLine
+// 2: endPoint is a crosspoint, no further investigation
+// 3: beginPoint is a crosspoint, no further investigation
+// 4: beginPoint and endPoint are crosspoints, no further investigation
+// 5: beginPoint is a crosspoint, need further investigation
+// 6: endPoint is a crosspoint, need further investigation
+
+    // The first switch will insert a crosspoint immediatly
+    switch (Take_Action1)
+    {
+        case 2: case 6: c1=lijn.m_b;
+                        Number_of_Crossings = 1;
+                        break;
+        case 3: case 5: c1=lijn.m_a;
+                        Number_of_Crossings = 1;
+                        break;
+        case 4:         c1=lijn.m_a;
+                        c2=lijn.m_b;
+                        Number_of_Crossings = 2;
+                        break;
+        default:
+                        break;
+    }
+
+    // This switch wil investigate the points of this wxLine in relation to lijn
+    // 1: Investigate results points in relation to the other wxLine
+    // 5: beginPoint is a crosspoint, need further investigation
+    // 6: endPoint is a crosspoint, need further investigation
+    switch (Take_Action1)
+    {
+        case 1: case 5: case 6:
+        {
+            Result_beginPoint = lijn.PointInLine(m_a,distance,Marge);
+            Result_endPoint   = lijn.PointInLine(m_b,distance,Marge);
+                Take_Action2 = ActionOnTable2(Result_beginPoint,Result_endPoint);
+            // return -1: Illegal combination
+            //         0: No action, no crosspoints
+            //         1: Calculate crosspoint
+            //         2: endPoint is a crosspoint
+            //         3: beginPoint is a crosspoint
+            //         4: beginPoint and endPoint are crosspoints
+            switch (Take_Action2)
+            {
+                // for the cases see the returnvalue of ActionTable2
+                case 1: {   // begin of scope to calculate the intersection
+                            double X, Y, Denominator;
+                            CalculateLineParameters();
+                            Denominator  = (m_AA * lijn.m_BB) - (lijn.m_AA * m_BB);
+                            // Denominator may not be 0
+                            assert(Denominator != 0.0);
+                            // Calculate intersection of both linesegments
+                            X = ((m_BB * lijn.m_CC) - (lijn.m_BB * m_CC)) / Denominator;
+                            Y = ((lijn.m_AA * m_CC) - (m_AA * lijn.m_CC)) / Denominator;
+
+                            c1.m_x=X;
+                            c1.m_y=Y;
+                         }
+                         Number_of_Crossings++;
+                         break;
+                case 2:  c2=m_a;
+                         Number_of_Crossings++;
+                         break;
+                case 3:  c2=m_b;
+                         Number_of_Crossings++;
+                         break;
+                case 4:  c1=m_a;
+                         c2=m_b;
+                         Number_of_Crossings = 2;
+                         break;
+            }
+        };
+        break;
+        default:
+             break;
+    }
+    return Number_of_Crossings; //This is de final number of crossings
+}
+
+//
+// test if a point lies in the linesegment. If the point isn't on the wxLine
+// the function returns a value that indicates on which side of the
+// wxLine the point is (in linedirection from first point to second point
+//
+// returns R_LEFT_SIDE, when point lies on the left side of the wxLine
+//         R_RIGHT_SIDE, when point lies on the right side of the wxLine
+//         R_ON_AREA, when point lies on the infinite wxLine within a range
+//         R_IN_AREA, when point lies in the area of the linesegment
+//        the returnvalues are declared in (wxLine.H)
+R_PointStatus wxLine::PointInLine(const wxPoint2DDouble& a_Point, double& Distance,double Marge)
+{
+    Distance=0;
+
+    // Point may not be the same
+    assert(m_a != m_b);
+
+    int Result_ofm_BBox=FALSE;
+    R_PointStatus Result_of_Online;
+
+    //quick test if point is begin or endpoint
+    if (a_Point == m_a || a_Point == m_b)
+        return R_IN_AREA;
+
+    // Checking if point is in bounding-box with marge
+    double xmin=wxMin(m_a.m_x,m_b.m_x);
+    double xmax=wxMax(m_a.m_x,m_b.m_x);
+    double ymin=wxMin(m_a.m_y,m_b.m_y);
+    double ymax=wxMax(m_a.m_y,m_b.m_y);
+
+    if (  a_Point.m_x >= (xmin - Marge) && a_Point.m_x <= (xmax + Marge) &&
+          a_Point.m_y >= (ymin - Marge) && a_Point.m_y <= (ymax + Marge) )
+        Result_ofm_BBox=TRUE;
+
+    // Checking if point is on the infinite wxLine
+    Result_of_Online = PointOnLine(a_Point, Distance, Marge);
+
+    // point in boundingbox of the wxLine and is on the wxLine then the point is R_IN_AREA
+    if ((Result_ofm_BBox) && (Result_of_Online == R_ON_AREA))
+        return R_IN_AREA;
+    else
+        return Result_of_Online;
+}
+
+
+//
+// test if a point lies on the wxLine. If the point isn't on the wxLine
+// the function returns a value that indicates on which side of the
+// wxLine the point is (in linedirection from first point to second point
+//
+// returns R_LEFT_SIDE, when point lies on the left side of the wxLine
+//         R_ON_AREA, when point lies on the infinite wxLine within a range
+//         R_RIGHT_SIDE, when point lies on the right side of the wxLine
+//        R_LEFT_SIDE , R_RIGHT_SIDE , R_ON_AREA
+R_PointStatus wxLine::PointOnLine(const wxPoint2DDouble& a_Point, double& Distance, double Marge)
+{
+    Distance=0;
+    // Point may not be queal
+    assert(m_a!=m_b);
+
+    //quick test if point is begin or endpoint
+    if (a_Point == m_a || a_Point == m_b)
+        return R_ON_AREA;
+
+    CalculateLineParameters();
+    // calculate the distance of a_Point in relation to the wxLine
+    Distance = (m_AA * a_Point.m_x)+(m_BB * a_Point.m_y) + m_CC;
+
+    if (Distance < -Marge)
+        return R_LEFT_SIDE;
+    else
+    {
+        if (Distance > Marge)
+            return R_RIGHT_SIDE;
+        else
+            return R_ON_AREA;
+    }
+}
+
+// makes a wxLine same as these
+// usage : wxLine1 = wxLine2;
+wxLine& wxLine::operator=(const wxLine& a_line)
+{
+    m_AA = a_line.m_AA;
+    m_BB = a_line.m_BB;
+    m_CC = a_line.m_CC;
+
+    m_a= a_line.m_a;
+    m_b= a_line.m_b;
+    m_valid_parameters = a_line.m_valid_parameters;
+    return *this;
+}
+
+void wxLine::OffsetContour(const wxLine& nextline,double factor,wxPoint2DDouble& offsetpoint)  const
+{
+    wxPoint2DDouble offs_begin(m_a);
+    wxPoint2DDouble offs_end(m_b);
+
+    wxPoint2DDouble offs_bgn_next(nextline.m_a);
+    wxPoint2DDouble offs_end_next(nextline.m_b);
+    // make a wxPoint2DDouble from this point
+
+    Virtual_Point(offs_begin,factor);
+    Virtual_Point(offs_end,factor);
+    wxLine  offs_currentline(offs_begin,offs_end);
+
+    nextline.Virtual_Point(offs_bgn_next,factor);
+    nextline.Virtual_Point(offs_end_next,factor);
+    wxLine  offs_nextline(offs_bgn_next, offs_end_next);
+
+    offs_nextline.CalculateLineParameters();
+    offs_currentline.CalculateLineParameters();
+    offs_currentline.Intersect(offs_nextline,offsetpoint);
+}
+
+// Return the position of the second wxLine compared to this wxLine
+// Result = IS_ON | IS_LEFT | IS_RIGHT
+// Here Left and Right is defined as being left or right from
+// the this wxLine towards the center (common) node
+// direction of vetors taken as begin to endpoint with end of this at
+// begin of wxLine two
+OUTPRODUCT wxLine::OutProduct(const wxLine& two,double accur)
+{
+    R_PointStatus uitp;
+    double distance;
+    if (two.m_a==two.m_b)
+        assert(0);
+    if (m_a==m_b)
+        assert(0);
+
+    uitp=PointOnLine(two.m_b, distance, accur);
+
+
+    /*double uitp=  (_x - first._x) * (third._y - _y) -
+                    (_y - first._y) * (third._x - _x);
+    if (uitp>0) return IS_LEFT;
+    if (uitp<0) return IS_RIGHT;
+    return IS_ON;*/
+
+    //depending on direction of this link (going to or coming from centre)
+    if (uitp==R_LEFT_SIDE)
+        return R_IS_LEFT;
+    if (uitp==R_RIGHT_SIDE)
+        return R_IS_RIGHT;
+    return R_IS_ON;
+}
+
+// Intersects two lines if a crossing return TRUE
+// else FALSE
+bool wxLine::Intersect(wxLine& lijn,wxPoint2DDouble& crossing)
+{
+    // lijn must exist
+    assert(m_valid_parameters);
+    assert(lijn.m_valid_parameters);
+
+    double X, Y, Denominator;
+    Denominator  = (m_AA * lijn.m_BB) - (lijn.m_AA * m_BB);
+    // Denominator may not be 0
+    if (Denominator == 0.0)
+        return FALSE;
+    // Calculate intersection of both linesegments
+    X = ((m_BB * lijn.m_CC) - (lijn.m_BB * m_CC)) / Denominator;
+    Y = ((lijn.m_AA * m_CC) - (m_AA * lijn.m_CC)) / Denominator;
+
+    crossing.m_x=X;
+    crossing.m_y=Y;
+    return TRUE;
+}
+
diff --git a/contrib/src/canvas/polygon.cpp b/contrib/src/canvas/polygon.cpp
new file mode 100644 (file)
index 0000000..efc3269
--- /dev/null
@@ -0,0 +1,1453 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        polygon.cpp
+// Author:      Klaas Holwerda
+// Created:     XX/XX/XX
+// Copyright:   2000 (c) Klaas Holwerda
+// Licence:     wxWindows Licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+    #pragma implementation "polygon.cpp"
+#endif
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#include "polygon.h"
+#include "liner.h"
+
+void ConvertSplinedPolygon(wxList* list, double Aber);
+void ConvertSplinedPolyline(wxList* list,double Aber);
+void ConvertSplinedPolygon(int& n, wxPoint2DDouble* points[], double Aber);
+static void GetLRO(const wxPoint2DDouble& P, const wxPoint2DDouble& p1, const wxPoint2DDouble& p2, int &LRO1, int &LRO2,const double marge);
+
+//----------------------------------------------------------------------------
+// wxCanvasPolyline
+//----------------------------------------------------------------------------
+
+wxCanvasPolyline::wxCanvasPolyline( int n,  wxPoint2DDouble points[])
+   : wxCanvasObject()
+{
+    m_n = n;
+    m_points = points;
+    m_pen = *wxBLACK_PEN;
+
+    CalcBoundingBox();
+}
+
+wxCanvasPolyline::~wxCanvasPolyline()
+{
+    delete m_points;
+}
+
+void wxCanvasPolyline::SetPosXY( double x, double y)
+{
+    double xo=m_points[0].m_x;
+    double yo=m_points[0].m_y;
+    int i;
+    for (i=0; i < m_n;i++)
+    {
+        m_points[i].m_x += (x-xo);
+        m_points[i].m_y += (y-yo);
+    }
+    CalcBoundingBox();
+}
+
+void wxCanvasPolyline::TransLate( double x, double y )
+{
+    int i;
+    for (i=0; i < m_n;i++)
+    {
+        m_points[i].m_x += x;
+        m_points[i].m_y += y;
+    }
+    CalcBoundingBox();
+}
+
+void wxCanvasPolyline::CalcBoundingBox()
+{
+    m_bbox.SetValid(FALSE);
+
+    int i;
+    for (i=0; i < m_n;i++)
+    {
+        m_bbox.Expand( m_points[i].m_x,m_points[i].m_y);
+    }
+
+    //include the pen width also
+    m_bbox.EnLarge(m_pen.GetWidth());
+}
+
+void wxCanvasPolyline::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    if (!m_visible) return;
+
+    int start_y = clip_y;
+    int end_y = clip_y+clip_height;
+
+    int start_x = clip_x;
+    int end_x = clip_x+clip_width;
+
+#if IMAGE_CANVAS
+#else
+    wxPoint *cpoints = new wxPoint[m_n];
+    int i;
+    for (i = 0; i < m_n; i++)
+    {
+        double x1;
+        double y1;
+        //transform to absolute
+        cworld->TransformPoint( m_points[i].m_x, m_points[i].m_y, x1, y1 );
+        //transform to device
+        cpoints[i].x = m_admin->LogicalToDeviceX(x1);
+        cpoints[i].y = m_admin->LogicalToDeviceY(y1);
+    }
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
+    int pw=m_pen.GetWidth();
+    m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
+    dc->SetPen(m_pen);
+    dc->DrawLines(m_n, cpoints, 0,0);
+    delete [] cpoints;
+    dc->SetPen(wxNullPen);
+    dc->DestroyClippingRegion();
+    m_pen.SetWidth(pw);
+#endif
+}
+
+void wxCanvasPolyline::WriteSVG( wxTextOutputStream &stream )
+{
+}
+
+wxCanvasObject* wxCanvasPolyline::IsHitWorld( double x, double y, double margin )
+{
+    if ((x >= m_bbox.GetMinX()-margin) &&
+        (x <= m_bbox.GetMaxX()+margin) &&
+        (y >= m_bbox.GetMinY()-margin) &&
+        (y <= m_bbox.GetMaxY()+margin)
+       )
+    {
+        wxPoint2DDouble P=wxPoint2DDouble(x,y);
+        if (PointOnPolyline(P,m_pen.GetWidth()/2+margin))
+            return this;
+        else
+            return (wxCanvasObject*) NULL;
+    }
+    return (wxCanvasObject*) NULL;
+}
+
+bool wxCanvasPolyline::PointOnPolyline(const wxPoint2DDouble& P, double margin)
+{
+    bool    result = FALSE;
+    double  distance;
+    wxPoint2DDouble p1,p2;
+
+    p2=m_points[0];
+    int i;
+    for (i = 0; i < m_n-1; i++)
+    {
+        p1=p2;
+        p2=m_points[i+1];
+        if (margin > sqrt(pow(p1.m_x-P.m_x,2)+pow(p1.m_y-P.m_y,2)))
+        {
+            result=TRUE;
+            break;
+        }
+        else if (!((p1.m_x == p2.m_x) && (p1.m_y == p2.m_y)))
+        {
+            wxLine line1(p1,p2);
+            if (line1.PointInLine(P,distance,margin) == R_IN_AREA)
+            {
+                result=TRUE;
+                break;
+            }
+        }
+    }
+
+    return result;
+}
+
+//----------------------------------------------------------------------------
+// wxCanvasPolygon
+//----------------------------------------------------------------------------
+
+wxCanvasPolygon::wxCanvasPolygon( int n, wxPoint2DDouble points[],bool splined)
+   : wxCanvasObject()
+{
+    m_n = n;
+    m_points = points;
+    m_brush = *wxBLACK_BRUSH;
+    m_pen = *wxTRANSPARENT_PEN;
+    m_textfg=*wxBLACK;
+    m_textbg=*wxWHITE;
+    m_transp=FALSE;
+    m_gpen=*wxBLACK_PEN;
+    m_gdistance=0;
+    m_gradient=FALSE;
+    m_spline = splined;
+
+    if (m_spline)
+    {
+        ConvertSplinedPolygon(m_n, &m_points, 10 );
+    }
+
+    CalcBoundingBox();
+}
+
+wxCanvasPolygon::~wxCanvasPolygon()
+{
+    delete m_points;
+}
+
+void wxCanvasPolygon::SetPosXY( double x, double y)
+{
+    double xo=m_points[0].m_x;
+    double yo=m_points[0].m_y;
+    int i;
+    for (i=0; i < m_n;i++)
+    {
+        m_points[i].m_x += (x-xo);
+        m_points[i].m_y += (y-yo);
+    }
+    CalcBoundingBox();
+}
+
+void wxCanvasPolygon::TransLate( double x, double y )
+{
+    int i;
+    for (i=0; i < m_n;i++)
+    {
+        m_points[i].m_x += x;
+        m_points[i].m_y += y;
+    }
+    CalcBoundingBox();
+}
+
+void wxCanvasPolygon::CalcBoundingBox()
+{
+
+    m_bbox.SetValid(FALSE);
+
+    int i;
+    for (i=0; i < m_n;i++)
+    {
+        m_bbox.Expand( m_points[i].m_x,m_points[i].m_y);
+    }
+
+    //include the pen width also
+    m_bbox.EnLarge(m_pen.GetWidth());
+}
+
+void wxCanvasPolygon::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    if (!m_visible) return;
+
+    int start_y = clip_y;
+    int end_y = clip_y+clip_height;
+
+    int start_x = clip_x;
+    int end_x = clip_x+clip_width;
+
+#if IMAGE_CANVAS
+#else
+    //one extra for drawlines in some cases
+    wxPoint *cpoints = new wxPoint[m_n+1];
+    int i;
+    for (i = 0; i < m_n; i++)
+    {
+        double x1;
+        double y1;
+        cworld->TransformPoint( m_points[i].m_x, m_points[i].m_y, x1, y1 );
+        cpoints[i].x = m_admin->LogicalToDeviceX(x1);
+        cpoints[i].y = m_admin->LogicalToDeviceY(y1);
+    }
+    double x1;
+    double y1;
+    cworld->TransformPoint( m_points[0].m_x, m_points[0].m_y, x1, y1 );
+    cpoints[m_n].x = m_admin->LogicalToDeviceX(x1);
+    cpoints[m_n].y = m_admin->LogicalToDeviceY(y1);
+
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
+    dc->SetBrush(m_brush);
+    int pw=m_pen.GetWidth();
+    m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
+    if ( m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE && m_transp)
+    {
+        //draw a transparent polygon
+        //leaf the pen not transparent, which i prefer
+        dc->SetPen( wxPen( *wxWHITE,m_admin->LogicalToDeviceXRel(pw), wxSOLID) );
+        dc->SetTextForeground(*wxBLACK);
+        dc->SetTextBackground(*wxWHITE);
+        dc->SetLogicalFunction(wxAND_INVERT);
+        // BLACK OUT the opaque pixels and leave the rest as is
+        dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE);
+        // Set background and foreground colors for fill pattern
+        //the previous blacked out pixels are now merged with the layer color
+        //while the non blacked out pixels stay as they are.
+        dc->SetTextForeground(*wxBLACK);
+        //now define what will be the color of the fillpattern parts that are not transparent
+        dc->SetTextBackground(m_textfg);
+        dc->SetLogicalFunction(wxOR);
+        //don't understand how but the outline is also depending on logicalfunction
+        dc->SetPen(m_pen);
+        dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE);
+    }
+    else if (m_gradient)
+    {
+        int pw2=m_gpen.GetWidth();
+        m_gpen.SetWidth(m_admin->LogicalToDeviceYRel(pw2));
+        FillPolygon(cworld,clip_x,clip_y,clip_width,clip_height );
+        if (m_pen.GetStyle() != wxTRANSPARENT)
+        {
+            dc->SetPen(m_pen);
+            dc->DrawLines(m_n+1, cpoints, 0,0);
+        }
+        m_gpen.SetWidth(pw2);
+    }
+    else
+    {
+        dc->SetPen(m_pen);
+        dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE);
+    }
+    delete [] cpoints;
+    dc->SetBrush(wxNullBrush);
+    dc->SetPen(wxNullPen);
+    dc->DestroyClippingRegion();
+    m_pen.SetWidth(pw);
+#endif
+}
+
+void wxCanvasPolygon::WriteSVG( wxTextOutputStream &stream )
+{
+}
+
+wxCanvasObject* wxCanvasPolygon::IsHitWorld( double x, double y, double margin )
+{
+    if ((x >= m_bbox.GetMinX()-margin) &&
+        (x <= m_bbox.GetMaxX()+margin) &&
+        (y >= m_bbox.GetMinY()-margin) &&
+        (y <= m_bbox.GetMaxY()+margin)
+       )
+    {
+        wxPoint2DDouble P=wxPoint2DDouble(x,y);
+        INOUTPOLY io=PointInPolygon(P, m_pen.GetWidth()/2+margin);
+        if (io == OUTSIDE_POLY)
+            return (wxCanvasObject*) NULL;
+        else
+            return this;
+    }
+    return (wxCanvasObject*) NULL;
+}
+
+INOUTPOLY wxCanvasPolygon::PointInPolygon(const wxPoint2DDouble& P, double marge)
+{
+    int     R_tot = 0, L_tot = 0;
+    int     p1_LRO, p2_LRO;
+    double  px = P.m_x, py = P.m_y;
+    double  Y_intersect;
+    wxPoint2DDouble p1,p2;
+
+    //iterate across points until we are sure that the given point is in or out
+    int i;
+    for (i = 0; i < m_n; i++)
+    {
+        p1 = m_points[i];
+        if (i == m_n-1)
+            p2 = m_points[0];
+        else
+            p2 = m_points[i+1];
+
+        //more accurate
+        GetLRO(P,p1,p2,p1_LRO,p2_LRO,marge/10);
+        if (p1_LRO != p2_LRO)
+        {
+            int L = 0, R = 0;
+            if (p2_LRO == -1) { R = -p1_LRO; L = 1; }
+            if (p2_LRO == 0) if (p1_LRO == 1) R = -1; else L = -1;
+            if (p2_LRO == 1) { R = 1; L = p1_LRO; }
+
+            // calculate intersection point with line for px
+            if (p1_LRO == 0)
+            {
+                if ((p1.m_y < (py + marge)) && (p1.m_y > (py - marge)))
+                    return ON_POLY;
+                else
+                    Y_intersect = p1.m_y;
+            }
+            else if (p2_LRO == 0)
+            {
+                if ((p2.m_y < (py + marge)) && (p2.m_y > (py - marge)))
+                    return ON_POLY;
+                else
+                    Y_intersect = p2.m_y;
+            }
+            else //both p2_LRO and p1_LRO not 0
+            {
+                if ((p1.m_y > (py + marge)) && (p2.m_y > (py + marge)))
+                    Y_intersect = p1.m_y; //a save value to check later
+                else if ((p1.m_y < (py- marge)) && (p2.m_y < (py - marge)))
+                    Y_intersect = p1.m_y; //a save value to check later
+                else //need to calculate intersection
+                {
+                    if (!((p1.m_x == p2.m_x) && (p1.m_y == p2.m_y)))
+                    {
+                        wxLine line1(p1,p2);
+                        line1.CalculateLineParameters();
+                        Y_intersect = line1.Calculate_Y(px);
+                    }
+                    else
+                         continue;
+                }
+            }
+            if (Y_intersect > (py + marge))
+            {
+                R_tot += R;
+                L_tot += L;
+            }
+            else if ((Y_intersect <= (py + marge)) && (Y_intersect >= (py - marge)))
+            {
+               return ON_POLY;
+            }
+        }
+    }
+
+    // geef het juiste resultaat terug
+    if (R_tot == 0)
+        if (L_tot == 0) return OUTSIDE_POLY;
+        else return ON_POLY;
+    else
+        if (L_tot == 0) return ON_POLY;
+        else return INSIDE_POLY;
+}
+
+//----------------------------------------------------------------------------
+// wxCanvasPolylineL
+//----------------------------------------------------------------------------
+
+wxCanvasPolylineL::wxCanvasPolylineL( wxList* points, bool spline )
+   : wxCanvasObject()
+{
+    m_lpoints = points;
+    m_pen = *wxBLACK_PEN;
+    m_spline=spline;
+    if (m_spline)
+        ConvertSplinedPolyline(m_lpoints, 10);
+    CalcBoundingBox();
+}
+
+wxCanvasPolylineL::~wxCanvasPolylineL()
+{
+    m_lpoints->DeleteContents(TRUE);
+    delete m_lpoints;
+}
+
+double wxCanvasPolylineL::GetPosX()
+{
+    wxNode *node = m_lpoints->GetFirst();
+    wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+    return point->m_x;
+}
+
+double wxCanvasPolylineL::GetPosY()
+{
+    wxNode *node = m_lpoints->GetFirst();
+    wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+    return point->m_y;
+}
+
+void wxCanvasPolylineL::SetPosXY( double x, double y )
+{
+    wxNode *node = m_lpoints->GetFirst();
+    wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+    double xo=point->m_x;
+    double yo=point->m_y;
+    while (node)
+    {
+        point = (wxPoint2DDouble*)node->Data();
+        point->m_x = point->m_x + x-xo;
+        point->m_y = point->m_y + y-yo;
+        node = node->GetNext();
+    }
+    CalcBoundingBox();
+}
+
+void wxCanvasPolylineL::TransLate( double x, double y )
+{
+    wxNode *node = m_lpoints->GetFirst();
+    while (node)
+    {
+        wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+        point->m_x += x;
+        point->m_y += y;
+        node = node->GetNext();
+    }
+    CalcBoundingBox();
+}
+
+void wxCanvasPolylineL::CalcBoundingBox()
+{
+    m_bbox.SetValid(FALSE);
+
+    wxNode *node = m_lpoints->GetFirst();
+    while (node)
+    {
+        wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+        m_bbox.Expand( point->m_x,point->m_y);
+        node = node->GetNext();
+    }
+
+    //include the pen width also
+    m_bbox.EnLarge(m_pen.GetWidth());
+}
+
+void wxCanvasPolylineL::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    if (!m_visible) return;
+
+    int start_y = clip_y;
+    int end_y = clip_y+clip_height;
+
+    int start_x = clip_x;
+    int end_x = clip_x+clip_width;
+
+#if IMAGE_CANVAS
+#else
+    int n=m_lpoints->GetCount();
+    wxPoint *cpoints = new wxPoint[n];
+
+    wxNode *node = m_lpoints->GetFirst();
+    int i=0;
+    while (node)
+    {
+        wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+        double x1;
+        double y1;
+        //transform to absolute
+        cworld->TransformPoint( point->m_x, point->m_y, x1, y1 );
+        //transform to device
+        cpoints[i].x = m_admin->LogicalToDeviceX(x1);
+        cpoints[i].y = m_admin->LogicalToDeviceY(y1);
+
+        node = node->GetNext();
+        i++;
+    }
+
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
+    int pw=m_pen.GetWidth();
+    m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
+    dc->SetPen(m_pen);
+    dc->DrawLines(n, cpoints, 0,0);
+    delete [] cpoints;
+    dc->SetPen(wxNullPen);
+    dc->DestroyClippingRegion();
+    m_pen.SetWidth(pw);
+#endif
+}
+
+void wxCanvasPolylineL::WriteSVG( wxTextOutputStream &stream )
+{
+}
+
+wxCanvasObject* wxCanvasPolylineL::IsHitWorld( double x, double y, double margin )
+{
+    if ((x >= m_bbox.GetMinX()-margin) &&
+        (x <= m_bbox.GetMaxX()+margin) &&
+        (y >= m_bbox.GetMinY()-margin) &&
+        (y <= m_bbox.GetMaxY()+margin)
+       )
+    {
+        wxPoint2DDouble P=wxPoint2DDouble(x,y);
+        if (PointOnPolyline(P,m_pen.GetWidth()/2+margin))
+            return this;
+        else
+            return (wxCanvasObject*) NULL;
+    }
+    return (wxCanvasObject*) NULL;
+}
+
+bool wxCanvasPolylineL::PointOnPolyline(const wxPoint2DDouble& P, double margin)
+{
+    bool    result = FALSE;
+    double  distance;
+    wxPoint2DDouble p1,p2;
+
+    wxNode *node = m_lpoints->GetFirst();
+    p2 = *(wxPoint2DDouble*)node->Data();
+    while (node && !result)
+    {
+        p1=p2;
+        node=node->GetNext();
+        if (!node) break;
+        p2 = *(wxPoint2DDouble*)node->Data();
+
+        if (margin > sqrt(pow(p1.m_x-P.m_x,2)+pow(p1.m_y-P.m_y,2)))
+            result=TRUE;
+        else if (!((p1.m_x == p2.m_x) && (p1.m_y == p2.m_y)))
+        {
+            wxLine line1(p1,p2);
+            if (line1.PointInLine(P,distance,margin) == R_IN_AREA)
+            result=TRUE;
+        }
+    }
+
+    return result;
+}
+
+//----------------------------------------------------------------------------
+// wxCanvasPolygon
+//----------------------------------------------------------------------------
+
+wxCanvasPolygonL::wxCanvasPolygonL( wxList* points, bool spline )
+   : wxCanvasObject()
+{
+    m_lpoints = points;
+    m_brush = *wxBLACK_BRUSH;
+    m_pen = *wxTRANSPARENT_PEN;
+    m_spline=spline;
+    m_textfg=*wxBLACK;
+    m_textbg=*wxWHITE;
+    m_transp=FALSE;
+
+    if (m_spline)
+        ConvertSplinedPolyline(m_lpoints, 10);
+    CalcBoundingBox();
+}
+
+wxCanvasPolygonL::~wxCanvasPolygonL()
+{
+    m_lpoints->DeleteContents(TRUE);
+    delete m_lpoints;
+}
+
+double wxCanvasPolygonL::GetPosX()
+{
+    wxNode *node = m_lpoints->GetFirst();
+    wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+    return point->m_x;
+}
+
+double wxCanvasPolygonL::GetPosY()
+{
+    wxNode *node = m_lpoints->GetFirst();
+    wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+    return point->m_y;
+}
+
+void wxCanvasPolygonL::SetPosXY( double x, double y )
+{
+    wxNode *node = m_lpoints->GetFirst();
+    wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+    double xo=point->m_x;
+    double yo=point->m_y;
+    while (node)
+    {
+        point = (wxPoint2DDouble*)node->Data();
+        point->m_x = point->m_x + x-xo;
+        point->m_y = point->m_y + y-yo;
+        node = node->GetNext();
+    }
+    CalcBoundingBox();
+}
+
+void wxCanvasPolygonL::TransLate( double x, double y )
+{
+    wxNode *node = m_lpoints->GetFirst();
+    while (node)
+    {
+        wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+        point->m_x += x;
+        point->m_y += y;
+        node = node->GetNext();
+    }
+    CalcBoundingBox();
+}
+
+void wxCanvasPolygonL::CalcBoundingBox()
+{
+
+    m_bbox.SetValid(FALSE);
+
+    wxNode *node = m_lpoints->GetFirst();
+    while (node)
+    {
+        wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+        m_bbox.Expand( point->m_x,point->m_y);
+        node = node->GetNext();
+    }
+
+    //include the pen width also
+    m_bbox.EnLarge(m_pen.GetWidth());
+}
+
+void wxCanvasPolygonL::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+    if (!m_visible) return;
+
+    int start_y = clip_y;
+    int end_y = clip_y+clip_height;
+
+    int start_x = clip_x;
+    int end_x = clip_x+clip_width;
+
+#if IMAGE_CANVAS
+#else
+    int n=m_lpoints->GetCount();
+    wxPoint *cpoints = new wxPoint[n];
+
+    wxNode *node = m_lpoints->GetFirst();
+    int i=0;
+    while (node)
+    {
+        wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
+        double x1;
+        double y1;
+        //transform to absolute
+        cworld->TransformPoint( point->m_x, point->m_y, x1, y1 );
+        //transform to device
+        cpoints[i].x = m_admin->LogicalToDeviceX(x1);
+        cpoints[i].y = m_admin->LogicalToDeviceY(y1);
+
+        node = node->GetNext();
+        i++;
+    }
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
+    dc->SetBrush(m_brush);
+    int pw=m_pen.GetWidth();
+    m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
+    if ( m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE && m_transp)
+    {
+        //draw a transparent polygon
+        //leaf the pen not transparent, which i prefer
+        dc->SetPen( wxPen( *wxWHITE,m_admin->LogicalToDeviceXRel(pw), wxSOLID) );
+        dc->SetTextForeground(*wxBLACK);
+        dc->SetTextBackground(*wxWHITE);
+        dc->SetLogicalFunction(wxAND_INVERT);
+        // BLACK OUT the opaque pixels and leave the rest as is
+        dc->DrawPolygon(n, cpoints, 0,0,wxWINDING_RULE);
+        // Set background and foreground colors for fill pattern
+        //the previous blacked out pixels are now merged with the layer color
+        //while the non blacked out pixels stay as they are.
+        dc->SetTextForeground(*wxBLACK);
+        //now define what will be the color of the fillpattern parts that are not transparent
+        dc->SetTextBackground(m_textfg);
+        dc->SetLogicalFunction(wxOR);
+        //don't understand how but the outline is also depending on logicalfunction
+        dc->SetPen(m_pen);
+        dc->DrawPolygon(n, cpoints, 0,0,wxWINDING_RULE);
+        dc->SetLogicalFunction(wxCOPY);
+    }
+    else
+    {
+        dc->SetPen(m_pen);
+        dc->SetTextForeground(m_textfg);
+        dc->SetTextBackground(m_textbg);
+        dc->DrawPolygon(n, cpoints, 0,0,wxWINDING_RULE);
+    }
+    delete [] cpoints;
+    dc->SetBrush(wxNullBrush);
+    dc->SetPen(wxNullPen);
+    dc->DestroyClippingRegion();
+    m_pen.SetWidth(pw);
+#endif
+}
+
+void wxCanvasPolygonL::WriteSVG( wxTextOutputStream &stream )
+{
+}
+
+static void GetLRO(const wxPoint2DDouble& P, const wxPoint2DDouble& p1, const wxPoint2DDouble& p2, int &LRO1, int &LRO2,const double marge)
+{
+    if (p1.m_x > (P.m_x + marge)) LRO1 = -1;        // beginnode is right of P
+    else
+        if (p1.m_x < (P.m_x - marge)) LRO1 = 1;     // beginnode is left of P
+        else LRO1 = 0;                              // beginnode is on vertical line through P
+
+    if (p2.m_x > (P.m_x + marge)) LRO2 = -1;        // endnode is right of P
+    else
+        if (p2.m_x < (P.m_x - marge)) LRO2 = 1;     // endnode is left of P
+        else LRO2 = 0;                              // endnode is on vertical line through P
+}
+
+wxCanvasObject* wxCanvasPolygonL::IsHitWorld( double x, double y, double margin )
+{
+    if ((x >= m_bbox.GetMinX()-margin) &&
+        (x <= m_bbox.GetMaxX()+margin) &&
+        (y >= m_bbox.GetMinY()-margin) &&
+        (y <= m_bbox.GetMaxY()+margin)
+       )
+    {
+        wxPoint2DDouble P=wxPoint2DDouble(x,y);
+        INOUTPOLY io=PointInPolygon(P,m_pen.GetWidth()/2 + margin);
+        if (io == OUTSIDE_POLY)
+            return (wxCanvasObject*) NULL;
+        else
+            return this;
+    }
+    return (wxCanvasObject*) NULL;
+}
+
+INOUTPOLY wxCanvasPolygonL::PointInPolygon(const wxPoint2DDouble& P, double marge)
+{
+    int     R_tot = 0, L_tot = 0;
+    int     p1_LRO, p2_LRO;
+    double  px = P.m_x, py = P.m_y;
+    double  Y_intersect;
+    wxPoint2DDouble p1,p2;
+
+    //iterate across points until we are sure that the given point is in or out
+    wxNode *node = m_lpoints->GetFirst();
+
+    while (node)
+    {
+        p1 = *(wxPoint2DDouble*)node->Data();
+        if (m_lpoints->GetLast() == node)
+        {
+            p2 = *(wxPoint2DDouble*)m_lpoints->GetFirst();
+        }
+        else
+        {
+            p2 = *(wxPoint2DDouble*)node->GetNext()->Data();
+        }
+
+        //more accurate
+        GetLRO(P,p1,p2,p1_LRO,p2_LRO,marge/10);
+        if (p1_LRO != p2_LRO)
+        {
+            int L = 0, R = 0;
+            if (p2_LRO == -1) { R = -p1_LRO; L = 1; }
+            if (p2_LRO == 0) if (p1_LRO == 1) R = -1; else L = -1;
+            if (p2_LRO == 1) { R = 1; L = p1_LRO; }
+
+            // calculate intersection point with line for px
+            if (p1_LRO == 0)
+            {
+                if ((p1.m_y < (py + marge)) && (p1.m_y > (py - marge)))
+                    return ON_POLY;
+                else
+                    Y_intersect = p1.m_y;
+            }
+            else if (p2_LRO == 0)
+            {
+                if ((p2.m_y < (py + marge)) && (p2.m_y > (py - marge)))
+                    return ON_POLY;
+                else
+                    Y_intersect = p2.m_y;
+            }
+            else //both p2_LRO and p1_LRO not 0
+            {
+                if ((p1.m_y > (py + marge)) && (p2.m_y > (py + marge)))
+                    Y_intersect = p1.m_y; //a save value to check later
+                else if ((p1.m_y < (py- marge)) && (p2.m_y < (py - marge)))
+                    Y_intersect = p1.m_y; //a save value to check later
+                else //need to calculate intersection
+                {
+                    if (!((p1.m_x == p2.m_x) && (p1.m_y == p2.m_y)))
+                    {
+                        wxLine line1(p1,p2);
+                        line1.CalculateLineParameters();
+                        Y_intersect = line1.Calculate_Y(px);
+                    }
+                    else
+                         continue;
+                }
+            }
+            if (Y_intersect > (py + marge))
+            {
+                R_tot += R;
+                L_tot += L;
+            }
+            else if ((Y_intersect <= (py + marge)) && (Y_intersect >= (py - marge)))
+            {
+               return ON_POLY;
+            }
+        }
+        node=node->Next();
+    }
+
+    // geef het juiste resultaat terug
+    if (R_tot == 0)
+        if (L_tot == 0) return OUTSIDE_POLY;
+        else return ON_POLY;
+    else
+        if (L_tot == 0) return ON_POLY;
+        else return INSIDE_POLY;
+}
+
+// ---------------------------------------------------------------------------
+// spline drawing code
+// ---------------------------------------------------------------------------
+
+static void gds_quadratic_spline(wxList *org,double a1, double b1, double a2, double b2,
+                         double a3, double b3, double a4, double b4,double aber);
+static void gds_clear_stack();
+static int gds_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
+                  double *y3, double *x4, double *y4);
+static void gds_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
+                    double x4, double y4);
+
+void ConvertSplinedPolygon(int& n, wxPoint2DDouble* points[], double Aber)
+{
+    wxList h;
+    int i;
+    for (i = 0; i < n; i++)
+    {
+        h.Append((wxObject*) new wxPoint2DDouble((*points)[i].m_x, (*points)[i].m_y));
+    }
+    delete *points;
+
+    ConvertSplinedPolygon(&h, Aber);
+
+    n=h.GetCount();
+    *points = new wxPoint2DDouble[n];
+    wxNode* node=h.GetFirst();
+    for (i = 0; i < n; i++)
+    {
+        wxNode* hh= node;
+        node = node->GetNext();
+        (*points)[i].m_x=((wxPoint2DDouble*) hh->GetData())->m_x;
+        (*points)[i].m_y=((wxPoint2DDouble*) hh->GetData())->m_y;
+        delete (wxPoint2DDouble*) hh->GetData();
+        h.DeleteNode(hh);
+    }
+}
+
+void ConvertSplinedPolygon(wxList* list, double Aber)
+{
+    wxPoint2DDouble* point;
+    double           cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
+    double           x1, y1, x2, y2;
+
+    if (list->GetCount() <2)
+        return;
+
+    wxNode* iter=list->GetLast();
+    x1 = ((wxPoint2DDouble*)iter->Data())->m_x;
+    y1 = ((wxPoint2DDouble*)iter->Data())->m_y;
+
+    iter=list->GetFirst();
+    x2 = ((wxPoint2DDouble*)iter->Data())->m_x;
+    y2 = ((wxPoint2DDouble*)iter->Data())->m_y;
+
+    point = new wxPoint2DDouble(x2,y2);
+    list->Append((wxObject*)point);
+
+    cx1 = (x1 + x2) / 2.0;
+    cy1 = (y1 + y2) / 2.0;
+    cx2 = (cx1 + x2) / 2.0;
+    cy2 = (cy1 + y2) / 2.0;
+
+    delete (wxPoint2DDouble*) iter->Data();
+    delete iter;
+    iter=list->GetFirst();
+    x1 = ((wxPoint2DDouble*)iter->Data())->m_x;
+    y1 = ((wxPoint2DDouble*)iter->Data())->m_y;
+    point = new wxPoint2DDouble(x1,y1);
+    list->Append((wxObject*)point);
+
+    int i=1;
+    int count=list->GetCount();
+    while (i < count)
+    {
+        x1 = x2;
+        y1 = y2;
+        x2 = ((wxPoint2DDouble*)iter->Data())->m_x;
+        y2 = ((wxPoint2DDouble*)iter->Data())->m_y;
+        cx4 = (x1 + x2) / 2.0;
+        cy4 = (y1 + y2) / 2.0;
+        cx3 = (x1 + cx4) / 2.0;
+        cy3 = (y1 + cy4) / 2.0;
+
+        gds_quadratic_spline(list,cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4,Aber);
+
+        cx1 = cx4;
+        cy1 = cy4;
+        cx2 = (cx1 + x2) / 2.0;
+        cy2 = (cy1 + y2) / 2.0;
+        delete (wxPoint2DDouble*)iter->Data();
+        delete iter;
+        iter=list->GetFirst();
+        i++;
+    }
+
+    iter=list->GetFirst();
+    delete (wxPoint2DDouble*)iter->Data();
+    delete iter;
+}
+
+void ConvertSplinedPolyline(wxList* list,double Aber)
+{
+    double           cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
+    double           x1, y1, x2, y2;
+
+
+    if (list->GetCount() <2)
+        return;
+
+
+
+    wxNode* iter=list->GetFirst();
+
+    x1 = ((wxPoint2DDouble*)iter->Data())->m_x;
+    y1 = ((wxPoint2DDouble*)iter->Data())->m_y;
+
+    delete (wxPoint2DDouble*)iter->Data();
+    delete iter;
+    iter=list->GetFirst();
+    x2 = ((wxPoint2DDouble*)iter->Data())->m_x;
+    y2 = ((wxPoint2DDouble*)iter->Data())->m_y;
+    cx1 = (x1 + x2) / 2.0;
+    cy1 = (y1 + y2) / 2.0;
+    cx2 = (cx1 + x2) / 2.0;
+    cy2 = (cy1 + y2) / 2.0;
+
+    wxPoint2DDouble* point = new wxPoint2DDouble(x1,y1);
+    list->Append((wxObject*)point);
+
+    delete (wxPoint2DDouble*)iter->Data();
+    delete iter;
+    iter=list->GetFirst();
+
+    int i=1;
+    int count=list->GetCount();
+    while (i < count)
+    {
+        x1 = x2;
+        y1 = y2;
+        x2 = ((wxPoint2DDouble*)iter->Data())->m_x;
+        y2 = ((wxPoint2DDouble*)iter->Data())->m_y;
+        cx4 = (x1 + x2) / 2.0;
+        cy4 = (y1 + y2) / 2.0;
+        cx3 = (x1 + cx4) / 2.0;
+        cy3 = (y1 + cy4) / 2.0;
+
+        gds_quadratic_spline(list,cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4,Aber);
+
+        cx1 = cx4;
+        cy1 = cy4;
+        cx2 = (cx1 + x2) / 2.0;
+        cy2 = (cy1 + y2) / 2.0;
+        delete (wxPoint2DDouble*)iter->Data();
+        delete iter;
+        iter=list->GetFirst();
+        i++;
+    }
+
+    point = new wxPoint2DDouble(cx1,cy1);
+    list->Append((wxObject*)point);
+
+    point = new wxPoint2DDouble(x2,y2);
+    list->Append((wxObject*)point);
+}
+
+/********************* CURVES FOR SPLINES *****************************
+
+  The following spline drawing routine is from
+
+    "An Algorithm for High-Speed Curve Generation"
+    by George Merrill Chaikin,
+    Computer Graphics and Image Processing, 3, Academic Press,
+    1974, 346-349.
+
+      and
+
+        "On Chaikin's Algorithm" by R. F. Riesenfeld,
+        Computer Graphics and Image Processing, 4, Academic Press,
+        1975, 304-310.
+
+***********************************************************************/
+
+#define     half(z1, z2)    ((z1+z2)/2.0)
+#define     THRESHOLD   5
+
+/* iterative version */
+
+void gds_quadratic_spline(wxList *org,double a1, double b1, double a2, double b2, double a3, double b3, double a4,
+                         double b4,double Aber)
+{
+    register double  xmid, ymid;
+    double           x1, y1, x2, y2, x3, y3, x4, y4;
+    wxPoint2DDouble* point;
+
+    gds_clear_stack();
+    gds_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
+
+    while (gds_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4))
+    {
+        xmid = half(x2, x3);
+        ymid = half(y2, y3);
+        if (fabs(x1 - xmid) < Aber && fabs(y1 - ymid) < Aber &&
+            fabs(xmid - x4) < Aber && fabs(ymid - y4) < Aber)
+        {
+            point = new wxPoint2DDouble(x1,y1);
+            org->Append((wxObject*)point);
+            point = new wxPoint2DDouble(xmid,ymid);
+            org->Append((wxObject*)point);
+        } else {
+            gds_spline_push(xmid, ymid, half(xmid, x3), half(ymid, y3),
+                half(x3, x4), half(y3, y4), x4, y4);
+            gds_spline_push(x1, y1, half(x1, x2), half(y1, y2),
+                half(x2, xmid), half(y2, ymid), xmid, ymid);
+        }
+    }
+}
+
+
+/* utilities used by spline drawing routines */
+
+
+typedef struct gds_spline_stack_struct {
+    double           x1, y1, x2, y2, x3, y3, x4, y4;
+}
+Stack;
+
+#define         SPLINE_STACK_DEPTH             20
+static Stack    gds_spline_stack[SPLINE_STACK_DEPTH];
+static Stack   *gds_stack_top;
+static int      gds_stack_count;
+
+static void gds_clear_stack()
+{
+    gds_stack_top = gds_spline_stack;
+    gds_stack_count = 0;
+}
+
+static void gds_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+{
+    gds_stack_top->x1 = x1;
+    gds_stack_top->y1 = y1;
+    gds_stack_top->x2 = x2;
+    gds_stack_top->y2 = y2;
+    gds_stack_top->x3 = x3;
+    gds_stack_top->y3 = y3;
+    gds_stack_top->x4 = x4;
+    gds_stack_top->y4 = y4;
+    gds_stack_top++;
+    gds_stack_count++;
+}
+
+int gds_spline_pop(double *x1, double *y1, double *x2, double *y2,
+                  double *x3, double *y3, double *x4, double *y4)
+{
+    if (gds_stack_count == 0)
+        return (0);
+    gds_stack_top--;
+    gds_stack_count--;
+    *x1 = gds_stack_top->x1;
+    *y1 = gds_stack_top->y1;
+    *x2 = gds_stack_top->x2;
+    *y2 = gds_stack_top->y2;
+    *x3 = gds_stack_top->x3;
+    *y3 = gds_stack_top->y3;
+    *x4 = gds_stack_top->x4;
+    *y4 = gds_stack_top->y4;
+    return (1);
+}
+
+void wxAET::CalculateLineParameters( const wxPoint2DDouble& p1 , const wxPoint2DDouble& p2 )
+{
+    double A = p2.m_y - p1.m_y; //A (y2-y1)
+    if (A == 0)
+    {
+        m_horizontal=TRUE;
+        m_BdivA=0;
+        m_CdivA=0;
+    }
+    else
+    {
+        m_horizontal=FALSE;
+        m_BdivA= (p1.m_x - p2.m_x)/A; //B (x1-x2)
+        //normalize
+        m_CdivA= ((p2.m_x*p1.m_y) - (p1.m_x*p2.m_y)) /A ;
+    }
+}
+
+void wxAET::CalculateXs( double y )
+{
+    m_xs= -m_BdivA * y - m_CdivA;
+}
+
+//use by polygon filling
+//moves the scanline up
+//index is the index of the point where the search begins
+//direction is +1 or -1 and indicates if the segment ascends or decends
+bool wxCanvasPolygon::MoveUp( double horline, int& index, int direction)
+{
+    int walk = (index + direction + m_n) % m_n;
+    while ( m_points[walk].m_y < horline )
+    {
+        if (m_points[walk].m_y < m_points[index].m_y )
+            return FALSE;
+        else
+        {
+            //modify index
+            index=walk;
+            walk = (index + direction + m_n) % m_n;
+        }
+    }
+    return TRUE;
+}
+
+//a crictical point is a point between a decending and a ascending segment
+//collect those points for filling later
+void wxCanvasPolygon::DetectCriticalPoints()
+{
+    //candidate for critical point
+    //true if Y is getting lower, unchanged i Y is unchanged
+    //and if Y becomes higher and candidate was true: it is a critical point
+    bool candidate = FALSE;
+    int i,j;
+
+    for ( i=0; i < m_n; i++)
+    {
+        //j next point
+        j= (i+1) % m_n;
+
+        //check if Y is smaller
+        if (m_points[i].m_y > m_points[j].m_y)
+            //we have a candidate
+            candidate=TRUE;
+        else if ( (m_points[i].m_y < m_points[j].m_y) && candidate)
+        {   //this is a critical point put in list
+            bool inserted=FALSE;
+            wxNode *node = m_CRlist.GetFirst();
+            while (node)
+            {
+                //sorted on smallest Y value
+                int* ind=(int*) node->GetData();
+                if (m_points[*ind].m_y > m_points[i].m_y)
+                {
+                    m_CRlist.Insert(node,(wxObject*) new int(i));
+                    inserted = TRUE;
+                    break;
+                }
+                node = node->GetNext();
+            }
+            if (!inserted)
+                m_CRlist.Append((wxObject*) new int(i));
+            candidate = FALSE;
+        }
+    }
+    if (candidate)
+    {
+        for ( i=0; i < m_n; i++)
+        {
+            //j next point
+            j= (i+1) % m_n;
+
+            //check if Y is smaller
+            if (m_points[i].m_y > m_points[j].m_y)
+                //we have a candidate
+                candidate=TRUE;
+            else if ( (m_points[i].m_y < m_points[j].m_y) && candidate)
+            {   //this is a critical point put in list
+                bool inserted=FALSE;
+                wxNode *node = m_CRlist.GetFirst();
+                while (node)
+                {
+                    //sorted on smallest Y value
+                    int* ind=(int*) node->GetData();
+                    if (m_points[*ind].m_y > m_points[i].m_y)
+                    {
+                        m_CRlist.Insert(node,(wxObject*) new int(i));
+                        inserted = TRUE;
+                        break;
+                    }
+                    node = node->GetNext();
+                }
+                if (!inserted)
+                    m_CRlist.Append((wxObject*) new int(i));
+                candidate = FALSE;
+            }
+        }
+    }
+}
+
+
+void wxCanvasPolygon::FillPolygon(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
+{
+#if IMAGE_CANVAS
+#else
+    int index;
+    //how much is on pixel in world coordinates
+
+    double scalefactor;
+    if (m_gdistance)
+        scalefactor=m_gdistance;
+    else
+        //abs here needed if yaxis is going up (always scan in world coordinates UP)
+        scalefactor=fabs(m_admin->DeviceToLogicalYRel(1)); //1 pixel height
+
+    wxDC *dc = m_admin->GetActive()->GetDC();
+    dc->SetClippingRegion( clip_x, clip_y, clip_width, clip_height );
+    wxPen  gradientpen=m_gpen;
+
+    int dred = m_textbg.Red()-m_textfg.Red();
+    int dgreen = m_textbg.Green()-m_textfg.Green();
+    int dblue = m_textbg.Blue()-m_textfg.Blue();
+
+    //total number of lines to go from m_textbg to m_textfg
+    //gives the following number of steps for the gradient color
+    int stepcol = (int) (m_bbox.GetHeight()/scalefactor);
+
+    DetectCriticalPoints();
+
+    double min;
+    double max;
+    if (cworld->IsIdentity())
+    {
+        //TODO do something with clipping region (inverse transform?)
+        //the next does not work, i don't know why
+        //min = wxMin (m_admin->DeviceToLogicalY(clip_y),m_admin->DeviceToLogicalY(clip_y+clip_height));
+        //max = wxMax (m_admin->DeviceToLogicalY(clip_y),m_admin->DeviceToLogicalY(clip_y+clip_height));
+        min= m_bbox.GetMinY();
+        max= m_bbox.GetMaxY();
+    }
+    else
+    {
+        min= m_bbox.GetMinY();
+        max= m_bbox.GetMaxY();
+    }
+
+    int curcol = (int)( (min - m_bbox.GetMinY())/scalefactor );
+
+    double i;
+    for ( i = min; i < max; i+=scalefactor)
+    {
+        wxNode *node = m_AETlist.GetFirst();
+        int count= m_AETlist.GetCount();
+        while (count > 0)
+        {
+            wxAET* ele = ((wxAET*)node->GetData());
+            index= ele->m_index;
+            int direction = ele->m_direction;
+            if (!MoveUp(i,index,direction))
+            {
+                wxNode* h = node;
+                //remove this node
+                node = node->GetNext();
+                m_AETlist.DeleteNode(h);
+            }
+            else
+            {
+                if (ele->m_index != index)
+                {
+                   ele->m_index=index;
+                   int h = (index + direction + m_n) % m_n;
+                   ele->CalculateLineParameters(m_points[h],m_points[index]);
+                }
+                if (ele->m_horizontal)
+                   ele->m_xs=m_points[index].m_x;
+                else
+                   ele->CalculateXs(i);
+                node = node->GetNext();
+            }
+            count--;
+        }
+
+        node = m_CRlist.GetFirst();
+        while (m_CRlist.GetCount() && m_points[*((int*)node->GetData())].m_y <=i )
+        {
+            int DI;
+            for ( DI = -1; DI <=1 ; DI+=2)
+            {
+                index=*((int*)node->GetData());
+                if (MoveUp(i,index,DI))
+                {
+                    wxAET* ele = new wxAET();
+                    ele->m_index=index;
+                    ele->m_direction=DI;
+                    int h = (index + DI + m_n) % m_n;
+                    ele->CalculateLineParameters(m_points[h],m_points[index]);
+                    if (ele->m_horizontal)
+                        ele->m_xs=m_points[index].m_x;
+                    else
+                        ele->CalculateXs(i);
+
+                    //insert in sorted order od m_xs
+                    bool inserted=FALSE;
+                    wxNode *node2 = m_AETlist.GetFirst();
+                    while (node2)
+                    {
+                        //sorted on smallest xs value
+                        if (ele->m_xs < ((wxAET*)node2->GetData())->m_xs)
+                        {
+                            m_AETlist.Insert(node2,(wxObject*) ele);
+                            inserted = TRUE;
+                            break;
+                        }
+                        node2 = node2->GetNext();
+                    }
+                    if (!inserted)
+                        m_AETlist.Append((wxObject*)ele);
+                }
+            }
+
+            wxNode* h= node;
+            node = node->GetNext();
+            m_CRlist.DeleteNode(h);
+        }
+
+        curcol++;
+        wxColour gradcol(m_textbg.Red()+dred*curcol/stepcol,
+                         m_textbg.Green()+dgreen*curcol/stepcol,
+                         m_textbg.Blue()+dblue*curcol/stepcol);
+        gradientpen.SetColour(gradcol);
+
+        //m_AETlist must be sorted in m_xs at this moment
+        //now draw all the line parts on one horizontal scanline (Winding Rule)
+        int out= 0;
+        node = m_AETlist.GetFirst();
+        while (node)
+        {
+            wxAET* ele = ((wxAET*)node->GetData());
+            out+=ele->m_direction;
+            if (out != 0)
+            {
+                double x1=ele->m_xs;
+                node = node->GetNext();
+                ele = ((wxAET*)node->GetData());
+                double x2=ele->m_xs;
+                dc->SetPen( gradientpen );
+                double wx1,wy1,wx2,wy2;
+                cworld->TransformPoint( x1, i, wx1, wy1 );
+                cworld->TransformPoint( x2, i, wx2, wy2 );
+                int dx1,dy1,dx2,dy2;
+                dx1 = m_admin->LogicalToDeviceX( wx1 );
+                dy1 = m_admin->LogicalToDeviceY( wy1 );
+                dx2 = m_admin->LogicalToDeviceX( wx2 );
+                dy2 = m_admin->LogicalToDeviceY( wy2 );
+
+                //TODO KKK need real line clipping here since line can be rotated.
+                if (0 && cworld->IsIdentity())
+                {
+                    if (dx1 < clip_x) dx1=clip_x;
+                    if (dx2 > clip_x + clip_width) dx2=clip_x + clip_width;
+                    if ((dy1 >  clip_y) && dy1 < clip_y + clip_height)
+                        dc->DrawLine( dx1, dy1, dx2, dy2 );
+                }
+                else
+                {
+                    dc->DrawLine( dx1, dy1, dx2, dy2 );
+                }
+
+            }
+            else
+                node = node->GetNext();
+        }
+    }
+
+    dc->DestroyClippingRegion();
+#endif
+}
+
+
+
+
+