Added GAL::DrawPolygon(SHAPE_POLY_SET) & GAL::DrawPolyLine(SHAPE_LINE_CHAIN)

This commit is contained in:
Maciej Suminski 2017-01-24 14:31:57 +01:00
parent 1eb7e7161e
commit 80956ef1e6
5 changed files with 153 additions and 89 deletions

View File

@ -3,6 +3,8 @@
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
* Copyright (C) 2017 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* CAIRO_GAL - Graphics Abstraction Layer for Cairo
*
@ -30,6 +32,7 @@
#include <gal/cairo/cairo_gal.h>
#include <gal/cairo/cairo_compositor.h>
#include <gal/definitions.h>
#include <geometry/shape_poly_set.h>
#include <limits>
@ -253,6 +256,13 @@ void CAIRO_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd
}
void CAIRO_GAL::DrawPolygon( const SHAPE_POLY_SET& aPolySet )
{
for( int i = 0; i < aPolySet.OutlineCount(); ++i )
drawPoly( aPolySet.COutline( i ) );
}
void CAIRO_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint )
{
@ -1050,6 +1060,25 @@ void CAIRO_GAL::drawPoly( const VECTOR2D aPointList[], int aListSize )
}
void CAIRO_GAL::drawPoly( const SHAPE_LINE_CHAIN& aLineChain )
{
if( aLineChain.PointCount() < 2 )
return;
const VECTOR2I start = aLineChain.CPoint( 0 );
cairo_move_to( currentContext, start.x, start.y );
for( int i = 1; i < aLineChain.PointCount(); ++i )
{
const VECTOR2I& p = aLineChain.CPoint( i );
cairo_line_to( currentContext, p.x, p.y );
}
flushPath();
isElementAdded = true;
}
unsigned int CAIRO_GAL::getNewGroupNumber()
{
wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),

View File

@ -30,6 +30,7 @@
#include <gal/opengl/utils.h>
#include <gal/definitions.h>
#include <gl_context_mgr.h>
#include <geometry/shape_poly_set.h>
#include <macros.h>
@ -619,123 +620,75 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn
void OPENGL_GAL::DrawPolyline( const std::deque<VECTOR2D>& aPointList )
{
if( aPointList.size() < 2 )
return;
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
std::deque<VECTOR2D>::const_iterator it = aPointList.begin();
// Start from the second point
for( ++it; it != aPointList.end(); ++it )
{
const VECTOR2D startEndVector = ( *it - *( it - 1 ) );
double lineAngle = startEndVector.Angle();
drawLineQuad( *( it - 1 ), *it );
// There is no need to draw line caps on both ends of polyline's segments
drawFilledSemiCircle( *( it - 1 ), lineWidth / 2, lineAngle + M_PI / 2 );
}
// ..and now - draw the ending cap
const VECTOR2D startEndVector = ( *( it - 1 ) - *( it - 2 ) );
double lineAngle = startEndVector.Angle();
drawFilledSemiCircle( *( it - 1 ), lineWidth / 2, lineAngle - M_PI / 2 );
drawPolyline( [&](int idx) { return aPointList[idx]; }, aPointList.size() );
}
void OPENGL_GAL::DrawPolyline( const VECTOR2D aPointList[], int aListSize )
{
if( aListSize < 2 )
return;
drawPolyline( [&](int idx) { return aPointList[idx]; }, aListSize );
}
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
// Start from the second point
for( int i = 1; i < aListSize; ++i )
{
const VECTOR2D startEndVector = ( aPointList[i] - aPointList[i - 1] );
double lineAngle = startEndVector.Angle();
drawLineQuad( aPointList[i - 1], aPointList[i] );
// There is no need to draw line caps on both ends of polyline's segments
drawFilledSemiCircle( aPointList[i - 1], lineWidth / 2, lineAngle + M_PI / 2 );
}
// ..and now - draw the ending cap
const VECTOR2D startEndVector = ( aPointList[aListSize - 1] - aPointList[aListSize - 2] );
double lineAngle = startEndVector.Angle();
drawFilledSemiCircle( aPointList[aListSize - 1], lineWidth / 2, lineAngle - M_PI / 2 );
void OPENGL_GAL::DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain )
{
drawPolyline( [&](int idx) { return aLineChain.CPoint(idx); }, aLineChain.PointCount() + 1 );
}
void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
{
currentManager->Shader( SHADER_NONE );
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aPointList.size()] );
GLdouble* ptr = points.get();
// Any non convex polygon needs to be tesselated
// for this purpose the GLU standard functions are used
TessParams params = { currentManager, tessIntersects };
gluTessBeginPolygon( tesselator, &params );
gluTessBeginContour( tesselator );
std::unique_ptr<GLdouble[]> points( new GLdouble[ 3 * aPointList.size() ] );
int v = 0;
for( std::deque<VECTOR2D>::const_iterator it = aPointList.begin(); it != aPointList.end(); ++it )
for( const VECTOR2D& p : aPointList )
{
points[v] = it->x;
points[v + 1] = it->y;
points[v + 2] = layerDepth;
gluTessVertex( tesselator, &points[v], &points[v] );
v += 3;
*ptr++ = p.x;
*ptr++ = p.y;
*ptr++ = layerDepth;
}
gluTessEndContour( tesselator );
gluTessEndPolygon( tesselator );
// Free allocated intersecting points
tessIntersects.clear();
// vertexList destroyed here
drawPolygon( points.get(), aPointList.size() );
}
void OPENGL_GAL::DrawPolygon( const VECTOR2D aPointList[], int aListSize )
{
currentManager->Shader( SHADER_NONE );
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
// Any non convex polygon needs to be tesselated
// for this purpose the GLU standard functions are used
TessParams params = { currentManager, tessIntersects };
gluTessBeginPolygon( tesselator, &params );
gluTessBeginContour( tesselator );
std::unique_ptr<GLdouble[]> points( new GLdouble[3 * aListSize] );
int v = 0;
const VECTOR2D* ptr = aPointList;
auto points = std::unique_ptr<GLdouble[]>( new GLdouble[3 * aListSize] );
GLdouble* target = points.get();
const VECTOR2D* src = aPointList;
for( int i = 0; i < aListSize; ++i )
{
points[v] = ptr->x;
points[v + 1] = ptr->y;
points[v + 2] = layerDepth;
gluTessVertex( tesselator, &points[v], &points[v] );
++ptr;
v += 3;
*target++ = src->x;
*target++ = src->y;
*target++ = layerDepth;
++src;
}
gluTessEndContour( tesselator );
gluTessEndPolygon( tesselator );
drawPolygon( points.get(), aListSize );
}
// Free allocated intersecting points
tessIntersects.clear();
// vertexList destroyed here
void OPENGL_GAL::DrawPolygon( const SHAPE_POLY_SET& aPolySet )
{
for( int j = 0; j < aPolySet.OutlineCount(); ++j )
{
const SHAPE_LINE_CHAIN& outline = aPolySet.COutline( j );
const int pointCount = outline.PointCount();
std::unique_ptr<GLdouble[]> points( new GLdouble[3 * pointCount] );
GLdouble* ptr = points.get();
for( int i = 0; i < outline.PointCount(); ++i )
{
const VECTOR2I& p = outline.CPoint( i );
*ptr++ = p.x;
*ptr++ = p.y;
*ptr++ = layerDepth;
}
drawPolygon( points.get(), pointCount );
}
}
@ -1341,6 +1294,63 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa
}
void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount )
{
currentManager->Shader( SHADER_NONE );
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
// Any non convex polygon needs to be tesselated
// for this purpose the GLU standard functions are used
TessParams params = { currentManager, tessIntersects };
gluTessBeginPolygon( tesselator, &params );
gluTessBeginContour( tesselator );
GLdouble* point = aPoints;
for( int i = 0; i < aPointCount; ++i )
{
gluTessVertex( tesselator, point, point );
point += 3; // 3 coordinates
}
gluTessEndContour( tesselator );
gluTessEndPolygon( tesselator );
// Free allocated intersecting points
tessIntersects.clear();
}
void OPENGL_GAL::drawPolyline( std::function<VECTOR2D (int)> aPointGetter, int aPointCount )
{
if( aPointCount < 2 )
return;
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
int i;
for( i = 1; i < aPointCount; ++i )
{
auto start = aPointGetter( i - 1 );
auto end = aPointGetter( i );
const VECTOR2D startEndVector = ( end - start );
double lineAngle = startEndVector.Angle();
drawLineQuad( start, end );
// There is no need to draw line caps on both ends of polyline's segments
drawFilledSemiCircle( start, lineWidth / 2, lineAngle + M_PI / 2 );
}
// ..and now - draw the ending cap
auto start = aPointGetter( i - 2 );
auto end = aPointGetter( i - 1 );
const VECTOR2D startEndVector = ( end - start );
double lineAngle = startEndVector.Angle();
drawFilledSemiCircle( end, lineWidth / 2, lineAngle - M_PI / 2 );
}
int OPENGL_GAL::drawBitmapChar( unsigned long aChar )
{
const float TEX_X = font_image.width;

View File

@ -120,10 +120,12 @@ public:
/// @copydoc GAL::DrawPolyline()
virtual void DrawPolyline( const std::deque<VECTOR2D>& aPointList ) override { drawPoly( aPointList ); }
virtual void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) override { drawPoly( aPointList, aListSize ); }
virtual void DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) override { drawPoly( aLineChain ); }
/// @copydoc GAL::DrawPolygon()
virtual void DrawPolygon( const std::deque<VECTOR2D>& aPointList ) override { drawPoly( aPointList ); }
virtual void DrawPolygon( const VECTOR2D aPointList[], int aListSize ) override { drawPoly( aPointList, aListSize ); }
virtual void DrawPolygon( const SHAPE_POLY_SET& aPolySet ) override;
/// @copydoc GAL::DrawCurve()
virtual void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA,
@ -397,6 +399,7 @@ private:
/// Drawing polygons & polylines is the same in cairo, so here is the common code
void drawPoly( const std::deque<VECTOR2D>& aPointList );
void drawPoly( const VECTOR2D aPointList[], int aListSize );
void drawPoly( const SHAPE_LINE_CHAIN& aLineChain );
/**
* @brief Returns a valid key that can be used as a new group number.

View File

@ -38,6 +38,9 @@
#include <gal/stroke_font.h>
#include <newstroke_font.h>
class SHAPE_LINE_CHAIN;
class SHAPE_POLY_SET;
namespace KIGFX
{
/**
@ -117,6 +120,7 @@ public:
*/
virtual void DrawPolyline( const std::deque<VECTOR2D>& aPointList ) {};
virtual void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) {};
virtual void DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) {};
/**
* @brief Draw a circle using world coordinates.
@ -152,6 +156,7 @@ public:
*/
virtual void DrawPolygon( const std::deque<VECTOR2D>& aPointList ) {};
virtual void DrawPolygon( const VECTOR2D aPointList[], int aListSize ) {};
virtual void DrawPolygon( const SHAPE_POLY_SET& aPolySet ) {};
/**
* @brief Draw a cubic bezier spline.

View File

@ -137,10 +137,12 @@ public:
/// @copydoc GAL::DrawPolyline()
virtual void DrawPolyline( const std::deque<VECTOR2D>& aPointList ) override;
virtual void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) override;
virtual void DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) override;
/// @copydoc GAL::DrawPolygon()
virtual void DrawPolygon( const std::deque<VECTOR2D>& aPointList ) override;
virtual void DrawPolygon( const VECTOR2D aPointList[], int aListSize ) override;
virtual void DrawPolygon( const SHAPE_POLY_SET& aPolySet ) override;
/// @copydoc GAL::DrawCurve()
virtual void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA,
@ -365,6 +367,21 @@ private:
*/
void drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle );
/**
* @param Generic way of drawing a polyline stored in different containers.
* @param aPointGetter is a function to obtain coordinates of n-th vertex.
* @param aPointCount is the number of points to be drawn.
*/
void drawPolyline( std::function<VECTOR2D (int)> aPointGetter, int aPointCount );
/**
* @brief Draws a filled polygon. It does not need the last point to have the same coordinates
* as the first one.
* @param aPoints is the vertices data (3 coordinates: x, y, z).
* @param aPointCount is the number of points.
*/
void drawPolygon( GLdouble* aPoints, int aPointCount );
/**
* @brief Draws a single character using bitmap font.
* Its main purpose is to be used in BitmapText() function.