From 80956ef1e66e324fe949178c00d91286a9fcbd54 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 24 Jan 2017 14:31:57 +0100 Subject: [PATCH] Added GAL::DrawPolygon(SHAPE_POLY_SET) & GAL::DrawPolyLine(SHAPE_LINE_CHAIN) --- common/gal/cairo/cairo_gal.cpp | 29 ++++ common/gal/opengl/opengl_gal.cpp | 188 ++++++++++++----------- include/gal/cairo/cairo_gal.h | 3 + include/gal/graphics_abstraction_layer.h | 5 + include/gal/opengl/opengl_gal.h | 17 ++ 5 files changed, 153 insertions(+), 89 deletions(-) diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index d9c765b355..9277f614bf 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -3,6 +3,8 @@ * * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors. + * Copyright (C) 2017 CERN + * @author Maciej Suminski * * CAIRO_GAL - Graphics Abstraction Layer for Cairo * @@ -30,6 +32,7 @@ #include #include #include +#include #include @@ -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::max(), diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 4e64d0e048..dcabed5f21 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -619,123 +620,75 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn void OPENGL_GAL::DrawPolyline( const std::deque& aPointList ) { - if( aPointList.size() < 2 ) - return; - - currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); - - std::deque::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& aPointList ) { - currentManager->Shader( SHADER_NONE ); - currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); + auto points = std::unique_ptr( 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, ¶ms ); - gluTessBeginContour( tesselator ); - - std::unique_ptr points( new GLdouble[ 3 * aPointList.size() ] ); - int v = 0; - - for( std::deque::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, ¶ms ); - gluTessBeginContour( tesselator ); - - std::unique_ptr points( new GLdouble[3 * aListSize] ); - int v = 0; - const VECTOR2D* ptr = aPointList; + auto points = std::unique_ptr( 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 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, ¶ms ); + 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 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; diff --git a/include/gal/cairo/cairo_gal.h b/include/gal/cairo/cairo_gal.h index 74e5227052..d93172c18e 100644 --- a/include/gal/cairo/cairo_gal.h +++ b/include/gal/cairo/cairo_gal.h @@ -120,10 +120,12 @@ public: /// @copydoc GAL::DrawPolyline() virtual void DrawPolyline( const std::deque& 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& 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& 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. diff --git a/include/gal/graphics_abstraction_layer.h b/include/gal/graphics_abstraction_layer.h index c6bc0643a4..66d3c8cdce 100644 --- a/include/gal/graphics_abstraction_layer.h +++ b/include/gal/graphics_abstraction_layer.h @@ -38,6 +38,9 @@ #include #include +class SHAPE_LINE_CHAIN; +class SHAPE_POLY_SET; + namespace KIGFX { /** @@ -117,6 +120,7 @@ public: */ virtual void DrawPolyline( const std::deque& 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& aPointList ) {}; virtual void DrawPolygon( const VECTOR2D aPointList[], int aListSize ) {}; + virtual void DrawPolygon( const SHAPE_POLY_SET& aPolySet ) {}; /** * @brief Draw a cubic bezier spline. diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index f685c6eaf5..f38f8d97fc 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -137,10 +137,12 @@ public: /// @copydoc GAL::DrawPolyline() virtual void DrawPolyline( const std::deque& 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& 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 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.