home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
wxos2233.zip
/
wxOS2-2_3_3.zip
/
wxWindows-2.3.3
/
contrib
/
src
/
canvas
/
polygon.cpp
< prev
Wrap
C/C++ Source or Header
|
2000-11-24
|
44KB
|
1,454 lines
/////////////////////////////////////////////////////////////////////////////
// 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 "wx/canvas/polygon.h"
#include "wx/canvas/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
}