StellarisWare Graphics Library Polygon
polygon.c
//*****************************************************************************
//
// polygon.c - Routines for drawing and filling polygons.
// Addition to StellarisWare library.
//
// Copyright (c) 2010 Mikk Leini, TUT Robotics Club NPO
//
// Polygon fill algorithm is based on Darel Rex Finley suggestions:
// http://www.alienryderflex.com/polygon_fill
//
//*****************************************************************************
#include "driverlib/debug.h"
#include "grlib/grlib.h"
//*****************************************************************************
//
//! \addtogroup primitives_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
//! Draws a polygon.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param pRect is a pointer to the array of structures containing the points
//! of the polygon.
//! \param ulNumPoints is a number of points in array.
//! \param bClosedLoop indicates wheter to draw line between the first and
//! the last point.
//!
//! This function draws lines between the consecutive points and if requiered
//! the line between the first and the last point.
//!
//! \return None.
//
//*****************************************************************************
void
GrPolyDraw(const tContext *pContext, const tPoint *pPoints,
unsigned long ulNumPoints, unsigned char ucClosedLoop)
{
unsigned long ulIdx;
//
// Check the arguments.
//
ASSERT(pContext);
ASSERT(pPoints);
ASSERT(sNumPoints > (bClosedLoop ? 2 : 1));
//
// Draw the lines between points
//
for(ulIdx = 0; ulIdx < ulNumPoints - 1; ulIdx++)
{
GrLineDraw(pContext, pPoints[ulIdx].sX, pPoints[ulIdx].sY,
pPoints[ulIdx + 1].sX, pPoints[ulIdx + 1].sY);
}
//
// Draw a closing line between first and last point?
//
if(ucClosedLoop)
{
GrLineDraw(pContext, pPoints[0].sX, pPoints[0].sY,
pPoints[ulNumPoints - 1].sX, pPoints[ulNumPoints - 1].sY);
}
}
//*****************************************************************************
//
//! Draws a filled polygon.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param pRect is a pointer to the array of structures containing the points
//! of the polygon.
//! \param ulNumPoints is a number of points in array.
//!
//! This function fills a polygon specified by the consecutive points.
//!
//! The clipping of the polygon to the clipping rectangle is performed within
//! this routine;
//!
//! \return None.
//
//*****************************************************************************
void
GrPolyFill(const tContext *pContext, const tPoint *pPoints,
unsigned long ulNumPoints)
{
unsigned long ulIdx, ulIdx2;
unsigned long ulNumNodes;
short sY;
short pNodeList[100];
short sSwap;
//
// Check the arguments.
//
ASSERT(pContext);
ASSERT(pPoints);
ASSERT(sNumPoints > 2);
//
// Loop through the rows of the clipping area.
//
for(sY = pContext->sClipRegion.sYMin; sY <= pContext->sClipRegion.sYMax; sY++)
{
//
// Build a list of nodes.
//
ulNumNodes = 0;
//
// Search for X coordinates of polygons on the current row.
//
for(ulIdx = 0; ulIdx < ulNumPoints; ulIdx++)
{
//
// Get the index of next point and wrap around points count.
//
ulIdx2 = (ulIdx + 1) % ulNumPoints;
//
// Check if the polygon line exists on the same row.
//
if(((pPoints[ulIdx].sY < sY) && (pPoints[ulIdx2].sY >= sY)) ||
((pPoints[ulIdx].sY >= sY) && (pPoints[ulIdx2].sY < sY)))
{
//
// Make sure nodes list isn't overflowed.
//
if(ulNumNodes >= 100) break;
//
// Calculate the intersection point X coordinate
// of the polygon edge.
//
pNodeList[ulNumNodes++] =
(pPoints[ulIdx].sX + (sY - pPoints[ulIdx].sY) *
(pPoints[ulIdx2].sX - pPoints[ulIdx].sX) /
(pPoints[ulIdx2].sY - pPoints[ulIdx].sY));
}
}
//
// Sort the nodes, via a simple “Bubble” sort.
//
ulIdx = 0;
while(ulIdx + 1 < ulNumNodes)
{
if(pNodeList[ulIdx] > pNodeList[ulIdx + 1])
{
sSwap = pNodeList[ulIdx];
pNodeList[ulIdx] = pNodeList[ulIdx + 1];
pNodeList[ulIdx + 1] = sSwap;
if(ulIdx)
{
ulIdx--;
}
}
else
{
ulIdx++;
}
}
//
// Fill the pixels between node pairs.
//
for(ulIdx = 0; ulIdx < ulNumNodes; ulIdx += 2)
{
//
// Break when lines go out of clipping region.
//
if(pNodeList[ulIdx] > pContext->sClipRegion.sXMax) break;
//
// Skip when line ends before clipping region.
//
if(pNodeList[ulIdx + 1] < pContext->sClipRegion.sXMin) continue;
//
// Clip the line from left.
//
if(pNodeList[ulIdx] < pContext->sClipRegion.sXMin)
{
pNodeList[ulIdx] = pContext->sClipRegion.sXMin;
}
//
// Clip the line from right.
//
if(pNodeList[ulIdx + 1] > pContext->sClipRegion.sXMax)
{
pNodeList[ulIdx + 1] = pContext->sClipRegion.sXMax;
}
//
// Call the low level horizontal line drawing routine.
//
DpyLineDrawH(pContext->pDisplay, pNodeList[ulIdx],
pNodeList[ulIdx + 1], sY, pContext->ulForeground);
}
}
}
//*****************************************************************************
//
//! Draws a triangle.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param pPoint1 is a pointer to the first point.
//! \param pPoint2 is a pointer to the second point.
//! \param pPoint3 is a pointer to the third point.
//!
//! This function draws a triangle specified by three points.
//!
//! \return None.
//
//*****************************************************************************
void
GrTriangleDraw(const tContext *pContext, const tPoint *pPoint1,
const tPoint *pPoint2, const tPoint *pPoint3)
{
tPoint pPoints[3];
pPoints[0] = *pPoint1;
pPoints[1] = *pPoint2;
pPoints[2] = *pPoint3;
GrPolyDraw(pContext, pPoints, 3, 1);
}
//*****************************************************************************
//
//! Draws a filled triangle.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param pPoint1 is a pointer to the first point.
//! \param pPoint2 is a pointer to the second point.
//! \param pPoint3 is a pointer to the third point.
//!
//! This function fills a triangle specified by three points.
//!
//! \return None.
//
//*****************************************************************************
void
GrTriangleFill(const tContext *pContext, const tPoint *pPoint1,
const tPoint *pPoint2, const tPoint *pPoint3)
{
tPoint pPoints[3];
pPoints[0] = *pPoint1;
pPoints[1] = *pPoint2;
pPoints[2] = *pPoint3;
GrPolyFill(pContext, pPoints, 3);
}
//*****************************************************************************
//
//! Draws a quad.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param pPoint1 is a pointer to the first point.
//! \param pPoint2 is a pointer to the second point.
//! \param pPoint3 is a pointer to the third point.
//! \param pPoint4 is a pointer to the fourth point.
//!
//! This function draws a quad specified by four points.
//!
//! \return None.
//
//*****************************************************************************
void
GrQuadDraw(const tContext *pContext, const tPoint *pPoint1,
const tPoint *pPoint2, const tPoint *pPoint3,
const tPoint *pPoint4)
{
tPoint pPoints[4];
pPoints[0] = *pPoint1;
pPoints[1] = *pPoint2;
pPoints[2] = *pPoint3;
pPoints[3] = *pPoint4;
GrPolyDraw(pContext, pPoints, 4, 1);
}
//*****************************************************************************
//
//! Draws a filled quad.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param pPoint1 is a pointer to the first point.
//! \param pPoint2 is a pointer to the second point.
//! \param pPoint3 is a pointer to the third point.
//! \param pPoint4 is a pointer to the fourth point.
//!
//! This function fills a quad specified by four points.
//!
//! The clipping of the polygon to the clipping rectangle is performed within
//! this routine;
//!
//! \return None.
//
//*****************************************************************************
void
GrQuadFill(const tContext *pContext, const tPoint *pPoint1,
const tPoint *pPoint2, const tPoint *pPoint3,
const tPoint *pPoint4)
{
tPoint pPoints[4];
pPoints[0] = *pPoint1;
pPoints[1] = *pPoint2;
pPoints[2] = *pPoint3;
pPoints[3] = *pPoint4;
GrPolyFill(pContext, pPoints, 4);
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
grlib.h
//*****************************************************************************
//
//! This structure defines the point.
//
//*****************************************************************************
typedef struct
{
//
//! The X coordinate of the point.
//
short sX;
//
//! The Y coordinate of the point.
//
short sY;
}
tPoint;
// Add these also:
extern void GrPolyDraw(const tContext *pContext, const tPoint *pPoints,
unsigned long ulNumPoints, unsigned char ucClosedLoop);
extern void GrPolyFill(const tContext *pContext, const tPoint *pPoints,
unsigned long ulNumPoints);
extern void GrTriangleDraw(const tContext *pContext, const tPoint *pPoint1,
const tPoint *pPoint2, const tPoint *pPoint3);
extern void GrTriangleFill(const tContext *pContext, const tPoint *pPoint1,
const tPoint *pPoint2, const tPoint *pPoint3);
extern void GrQuadDraw(const tContext *pContext, const tPoint *pPoint1,
const tPoint *pPoint2, const tPoint *pPoint3,
const tPoint *pPoint4);
extern void GrQuadFill(const tContext *pContext, const tPoint *pPoint1,
const tPoint *pPoint2, const tPoint *pPoint3,
const tPoint *pPoint4);