Answer To: Data collection and display system (Collect a data item periodically (ex. temperature, value of...
Karthi answered on Jul 24 2021
cpp/pbPlots.cpp
cpp/pbPlots.cpp
// Downloaded from https://repo.progsbase.com - Code Developed Using progsbase.
#include "pbPlots.hpp"
using namespace std;
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
bool CropLineWithinBoundary(NumberReference *x1Ref, NumberReference *y1Ref, NumberReference *x2Ref, NumberReference *y2Ref, double xMin, double xMax, double yMin, double yMax){
double x1, y1, x2, y2;
bool success, p1In, p2In;
double dx, dy, f1, f2, f3, f4, f;
x1 = x1Ref->numberValue;
y1 = y1Ref->numberValue;
x2 = x2Ref->numberValue;
y2 = y2Ref->numberValue;
p1In = x1 >= xMin && x1 <= xMax && y1 >= yMin && y1 <= yMax;
p2In = x2 >= xMin && x2 <= xMax && y2 >= yMin && y2 <= yMax;
if(p1In && p2In){
success = true;
}else if( !p1In && p2In){
dx = x1 - x2;
dy = y1 - y2;
if(dx != 0.0){
f1 = (xMin - x2)/dx;
f2 = (xMax - x2)/dx;
}else{
f1 = 1.0;
f2 = 1.0;
}
if(dy != 0.0){
f3 = (yMin - y2)/dy;
f4 = (yMax - y2)/dy;
}else{
f3 = 1.0;
f4 = 1.0;
}
if(f1 < 0.0){
f1 = 1.0;
}
if(f2 < 0.0){
f2 = 1.0;
}
if(f3 < 0.0){
f3 = 1.0;
}
if(f4 < 0.0){
f4 = 1.0;
}
f = fmin(f1, fmin(f2, fmin(f3, f4)));
x1 = x2 + f*dx;
y1 = y2 + f*dy;
success = true;
}else if(p1In && !p2In ){
dx = x2 - x1;
dy = y2 - y1;
if(dx != 0.0){
f1 = (xMin - x1)/dx;
f2 = (xMax - x1)/dx;
}else{
f1 = 1.0;
f2 = 1.0;
}
if(dy != 0.0){
f3 = (yMin - y1)/dy;
f4 = (yMax - y1)/dy;
}else{
f3 = 1.0;
f4 = 1.0;
}
if(f1 < 0.0){
f1 = 1.0;
}
if(f2 < 0.0){
f2 = 1.0;
}
if(f3 < 0.0){
f3 = 1.0;
}
if(f4 < 0.0){
f4 = 1.0;
}
f = fmin(f1, fmin(f2, fmin(f3, f4)));
x2 = x1 + f*dx;
y2 = y1 + f*dy;
success = true;
}else{
success = false;
}
x1Ref->numberValue = x1;
y1Ref->numberValue = y1;
x2Ref->numberValue = x2;
y2Ref->numberValue = y2;
return success;
}
double IncrementFromCoordinates(double x1, double y1, double x2, double y2){
return (x2 - x1)/(y2 - y1);
}
double InterceptFromCoordinates(double x1, double y1, double x2, double y2){
double a, b;
a = IncrementFromCoordinates(x1, y1, x2, y2);
b = y1 - a*x1;
return b;
}
vector *Get8HighContrastColors(){
vector *colors;
colors = new vector (8.0);
colors->at(0) = CreateRGBColor(3.0/256.0, 146.0/256.0, 206.0/256.0);
colors->at(1) = CreateRGBColor(253.0/256.0, 83.0/256.0, 8.0/256.0);
colors->at(2) = CreateRGBColor(102.0/256.0, 176.0/256.0, 50.0/256.0);
colors->at(3) = CreateRGBColor(208.0/256.0, 234.0/256.0, 43.0/256.0);
colors->at(4) = CreateRGBColor(167.0/256.0, 25.0/256.0, 75.0/256.0);
colors->at(5) = CreateRGBColor(254.0/256.0, 254.0/256.0, 51.0/256.0);
colors->at(6) = CreateRGBColor(134.0/256.0, 1.0/256.0, 175.0/256.0);
colors->at(7) = CreateRGBColor(251.0/256.0, 153.0/256.0, 2.0/256.0);
return colors;
}
void DrawFilledRectangleWithBorder(RGBABitmapImage *image, double x, double y, double w, double h, RGBA *borderColor, RGBA *fillColor){
if(h > 0.0 && w > 0.0){
DrawFilledRectangle(image, x, y, w, h, fillColor);
DrawRectangle1px(image, x, y, w, h, borderColor);
}
}
RGBABitmapImageReference *CreateRGBABitmapImageReference(){
RGBABitmapImageReference *reference;
reference = new RGBABitmapImageReference();
reference->image = new RGBABitmapImage();
reference->image->x = new vector (0.0);
return reference;
}
bool RectanglesOverlap(Rectangle *r1, Rectangle *r2){
bool overlap;
overlap = false;
overlap = overlap || (r2->x1 >= r1->x1 && r2->x1 <= r1->x2 && r2->y1 >= r1->y1 && r2->y1 <= r1->y2);
overlap = overlap || (r2->x2 >= r1->x1 && r2->x2 <= r1->x2 && r2->y1 >= r1->y1 && r2->y1 <= r1->y2);
overlap = overlap || (r2->x1 >= r1->x1 && r2->x1 <= r1->x2 && r2->y2 >= r1->y1 && r2->y2 <= r1->y2);
overlap = overlap || (r2->x2 >= r1->x1 && r2->x2 <= r1->x2 && r2->y2 >= r1->y1 && r2->y2 <= r1->y2);
return overlap;
}
Rectangle *CreateRectangle(double x1, double y1, double x2, double y2){
Rectangle *r;
r = new Rectangle();
r->x1 = x1;
r->y1 = y1;
r->x2 = x2;
r->y2 = y2;
return r;
}
void CopyRectangleValues(Rectangle *rd, Rectangle *rs){
rd->x1 = rs->x1;
rd->y1 = rs->y1;
rd->x2 = rs->x2;
rd->y2 = rs->y2;
}
void DrawXLabelsForPriority(double p, double xMin, double oy, double xMax, double xPixelMin, double xPixelMax, NumberReference *nextRectangle, RGBA *gridLabelColor, RGBABitmapImage *canvas, vector *xGridPositions, StringArrayReference *xLabels, NumberArrayReference *xLabelPriorities, vector *occupied, bool textOnBottom){
bool overlap, currentOverlaps;
double i, j, x, px, padding;
vector *text;
Rectangle *r;
r = new Rectangle();
padding = 10.0;
overlap = false;
for(i = 0.0; i < xLabels->stringArray->size(); i = i + 1.0){
if(xLabelPriorities->numberArray->at(i) == p){
x = xGridPositions->at(i);
px = MapXCoordinate(x, xMin, xMax, xPixelMin, xPixelMax);
text = xLabels->stringArray->at(i)->string;
r->x1 = floor(px - GetTextWidth(text)/2.0);
if(textOnBottom){
r->y1 = floor(oy + 5.0);
}else{
r->y1 = floor(oy - 20.0);
}
r->x2 = r->x1 + GetTextWidth(text);
r->y2 = r->y1 + GetTextHeight(text);
/* Add padding */
r->x1 = r->x1 - padding;
r->y1 = r->y1 - padding;
r->x2 = r->x2 + padding;
r->y2 = r->y2 + padding;
currentOverlaps = false;
for(j = 0.0; j < nextRectangle->numberValue; j = j + 1.0){
currentOverlaps = currentOverlaps || RectanglesOverlap(r, occupied->at(j));
}
if( !currentOverlaps && p == 1.0){
DrawText(canvas, r->x1 + padding, r->y1 + padding, text, gridLabelColor);
CopyRectangleValues(occupied->at(nextRectangle->numberValue), r);
nextRectangle->numberValue = nextRectangle->numberValue + 1.0;
}
overlap = overlap || currentOverlaps;
}
}
if( !overlap && p != 1.0){
for(i = 0.0; i < xGridPositions->size(); i = i + 1.0){
x = xGridPositions->at(i);
px = MapXCoordinate(x, xMin, xMax, xPixelMin, xPixelMax);
if(xLabelPriorities->numberArray->at(i) == p){
text = xLabels->stringArray->at(i)->string;
r->x1 = floor(px - GetTextWidth(text)/2.0);
if(textOnBottom){
r->y1 = floor(oy + 5.0);
}else{
r->y1 = floor(oy - 20.0);
}
r->x2 = r->x1 + GetTextWidth(text);
r->y2 = r->y1 + GetTextHeight(text);
DrawText(canvas, r->x1, r->y1, text, gridLabelColor);
CopyRectangleValues(occupied->at(nextRectangle->numberValue), r);
nextRectangle->numberValue = nextRectangle->numberValue + 1.0;
}
}
}
}
void DrawYLabelsForPriority(double p, double yMin, double ox, double yMax, double yPixelMin, double yPixelMax, NumberReference *nextRectangle, RGBA *gridLabelColor, RGBABitmapImage *canvas, vector *yGridPositions, StringArrayReference *yLabels, NumberArrayReference *yLabelPriorities, vector *occupied, bool textOnLeft){
bool overlap, currentOverlaps;
double i, j, y, py, padding;
vector *text;
Rectangle *r;
r = new Rectangle();
padding = 10.0;
overlap = false;
for(i = 0.0; i < yLabels->stringArray->size(); i = i + 1.0){
if(yLabelPriorities->numberArray->at(i) == p){
y = yGridPositions->at(i);
py = MapYCoordinate(y, yMin, yMax, yPixelMin, yPixelMax);
text = yLabels->stringArray->at(i)->string;
if(textOnLeft){
r->x1 = floor(ox - GetTextWidth(text) - 10.0);
}else{
r->x1 = floor(ox + 10.0);
}
r->y1 = floor(py - 6.0);
r->x2 = r->x1 + GetTextWidth(text);
r->y2 = r->y1 + GetTextHeight(text);
/* Add padding */
r->x1 = r->x1 - padding;
r->y1 = r->y1 - padding;
r->x2 = r->x2 + padding;
r->y2 = r->y2 + padding;
currentOverlaps = false;
for(j = 0.0; j < nextRectangle->numberValue; j = j + 1.0){
currentOverlaps = currentOverlaps || RectanglesOverlap(r, occupied->at(j));
}
/* Draw labels with priority 1 if they do not overlap anything else. */
if( !currentOverlaps && p == 1.0){
DrawText(canvas, r->x1 + padding, r->y1 + padding, text, gridLabelColor);
CopyRectangleValues(occupied->at(nextRectangle->numberValue), r);
nextRectangle->numberValue = nextRectangle->numberValue + 1.0;
}
overlap = overlap || currentOverlaps;
}
}
if( !overlap && p != 1.0){
for(i = 0.0; i < yGridPositions->size(); i = i + 1.0){
y = yGridPositions->at(i);
py = MapYCoordinate(y, yMin, yMax, yPixelMin, yPixelMax);
if(yLabelPriorities->numberArray->at(i) == p){
text = yLabels->stringArray->at(i)->string;
if(textOnLeft){
r->x1 = floor(ox - GetTextWidth(text) - 10.0);
}else{
r->x1 = floor(ox + 10.0);
}
r->y1 = floor(py - 6.0);
r->x2 = r->x1 + GetTextWidth(text);
r->y2 = r->y1 + GetTextHeight(text);
DrawText(canvas, r->x1, r->y1, text, gridLabelColor);
CopyRectangleValues(occupied->at(nextRectangle->numberValue), r);
nextRectangle->numberValue = nextRectangle->numberValue + 1.0;
}
}
}
}
vector *ComputeGridLinePositions(double cMin, double cMax, StringArrayReference *labels, NumberArrayReference *priorities){
vector *positions;
double cLength, p, pMin, pMax, pInterval, pNum, i, num, rem, priority, mode;
cLength = cMax - cMin;
p = floor(log10(cLength));
pInterval = pow(10.0, p);
/* gives 10-1 lines for 100-10 diff */
pMin = ceil(cMin/pInterval)*pInterval;
pMax = floor(cMax/pInterval)*pInterval;
pNum = Round((pMax - pMin)/pInterval + 1.0);
mode = 1.0;
if(pNum <= 3.0){
p = floor(log10(cLength) - 1.0);
/* gives 100-10 lines for 100-10 diff */
pInterval = pow(10.0, p);
pMin = ceil(cMin/pInterval)*pInterval;
pMax = floor(cMax/pInterval)*pInterval;
pNum = Round((pMax - pMin)/pInterval + 1.0);
mode = 4.0;
}else if(pNum <= 6.0){
p = floor(log10(cLength));
pInterval = pow(10.0, p)/4.0;
/* gives 40-5 lines for 100-10 diff */
pMin = ceil(cMin/pInterval)*pInterval;
pMax = floor(cMax/pInterval)*pInterval;
pNum = Round((pMax - pMin)/pInterval + 1.0);
mode = 3.0;
}else if(pNum <= 10.0){
p = floor(log10(cLength));
pInterval = pow(10.0, p)/2.0;
/* gives 20-3 lines for 100-10 diff */
pMin = ceil(cMin/pInterval)*pInterval;
pMax = floor(cMax/pInterval)*pInterval;
pNum = Round((pMax - pMin)/pInterval + 1.0);
mode = 2.0;
}
positions = new vector (pNum);
labels->stringArray = new vector (pNum);
priorities->numberArray = new vector (pNum);
for(i = 0.0; i < pNum; i = i + 1.0){
num = pMin + pInterval*i;
positions->at(i) = num;
/* Always print priority 1 labels. Only draw priority 2 if they can all be drawn. Then, only draw priority 3 if they can all be drawn. */
priority = 1.0;
/* Prioritize x.25, x.5 and x.75 lower. */
if(mode == 2.0 || mode == 3.0){
rem = fmod(abs(round(num/pow(10.0, p - 2.0))), 100.0);
priority = 1.0;
if(rem == 50.0){
priority = 2.0;
}else if(rem == 25.0 || rem == 75.0){
priority = 3.0;
}
}
/* Prioritize x.1-x.4 and x.6-x.9 lower */
if(mode == 4.0){
rem = fmod(abs(Round(num/pow(10.0, p))), 10.0);
priority = 1.0;
if(rem == 1.0 || rem == 2.0 || rem == 3.0 || rem == 4.0 || rem == 6.0 || rem == 7.0 || rem == 8.0 || rem == 9.0){
priority = 2.0;
}
}
/* 0 has lowest priority. */
if(EpsilonCompare(num, 0.0, pow(10.0, p - 5.0))){
priority = 3.0;
}
priorities->numberArray->at(i) = priority;
/* The label itself. */
labels->stringArray->at(i) = new StringReference();
if(p < 0.0){
if(mode == 2.0 || mode == 3.0){
num = RoundToDigits(num, -(p - 1.0));
}else{
num = RoundToDigits(num, -p);
}
}
labels->stringArray->at(i)->string = CreateStringDecimalFromNumber(num);
}
return positions;
}
double MapYCoordinate(double y, double yMin, double yMax, double yPixelMin, double yPixelMax){
double yLength, yPixelLength;
yLength = yMax - yMin;
yPixelLength = yPixelMax - yPixelMin;
y = y - yMin;
y = y*yPixelLength/yLength;
y = yPixelLength - y;
y = y + yPixelMin;
return y;
}
double MapXCoordinate(double x, double xMin, double xMax, double xPixelMin, double xPixelMax){
double xLength, xPixelLength;
xLength = xMax - xMin;
xPixelLength = xPixelMax - xPixelMin;
x = x - xMin;
x = x*xPixelLength/xLength;
x = x + xPixelMin;
return x;
}
double MapXCoordinateAutoSettings(double x, RGBABitmapImage *image, vector *xs){
return MapXCoordinate(x, GetMinimum(xs), GetMaximum(xs), GetDefaultPaddingPercentage()*ImageWidth(image), (1.0 - GetDefaultPaddingPercentage())*ImageWidth(image));
}
double MapYCoordinateAutoSettings(double y, RGBABitmapImage *image, vector *ys){
return MapYCoordinate(y, GetMinimum(ys), GetMaximum(ys), GetDefaultPaddingPercentage()*ImageHeight(image), (1.0 - GetDefaultPaddingPercentage())*ImageHeight(image));
}
double MapXCoordinateBasedOnSettings(double x, ScatterPlotSettings *settings){
double xMin, xMax, xPadding, xPixelMin, xPixelMax;
Rectangle *boundaries;
boundaries = new Rectangle();
ComputeBoundariesBasedOnSettings(settings, boundaries);
xMin = boundaries->x1;
xMax = boundaries->x2;
if(settings->autoPadding){
xPadding = floor(GetDefaultPaddingPercentage()*settings->width);
}else{
xPadding = settings->xPadding;
}
xPixelMin = xPadding;
xPixelMax = settings->width - xPadding;
return MapXCoordinate(x, xMin, xMax, xPixelMin, xPixelMax);
}
double MapYCoordinateBasedOnSettings(double y, ScatterPlotSettings *settings){
double yMin, yMax, yPadding, yPixelMin, yPixelMax;
Rectangle *boundaries;
boundaries = new Rectangle();
ComputeBoundariesBasedOnSettings(settings, boundaries);
yMin = boundaries->y1;
yMax = boundaries->y2;
if(settings->autoPadding){
yPadding = floor(GetDefaultPaddingPercentage()*settings->height);
}else{
yPadding = settings->yPadding;
}
yPixelMin = yPadding;
yPixelMax = settings->height - yPadding;
return MapYCoordinate(y, yMin, yMax, yPixelMin, yPixelMax);
}
double GetDefaultPaddingPercentage(){
return 0.10;
}
void DrawText(RGBABitmapImage *canvas, double x, double y, vector *text, RGBA *color){
double i, charWidth, spacing;
charWidth = 8.0;
spacing = 2.0;
for(i = 0.0; i < text->size(); i = i + 1.0){
DrawAsciiCharacter(canvas, x + i*(charWidth + spacing), y, text->at(i), color);
}
}
void DrawTextUpwards(RGBABitmapImage *canvas, double x, double y, vector *text, RGBA *color){
RGBABitmapImage *buffer, *rotated;
buffer = CreateImage(GetTextWidth(text), GetTextHeight(text), GetTransparent());
DrawText(buffer, 0.0, 0.0, text, color);
rotated = RotateAntiClockwise90Degrees(buffer);
DrawImageOnImage(canvas, rotated, x, y);
DeleteImage(buffer);
DeleteImage(rotated);
}
ScatterPlotSettings *GetDefaultScatterPlotSettings(){
ScatterPlotSettings *settings;
settings = new ScatterPlotSettings();
settings->autoBoundaries = true;
settings->xMax = 0.0;
settings->xMin = 0.0;
settings->yMax = 0.0;
settings->yMin = 0.0;
settings->autoPadding = true;
settings->xPadding = 0.0;
settings->yPadding = 0.0;
settings->title = toVector(L"");
settings->xLabel = toVector(L"");
settings->yLabel = toVector(L"");
settings->scatterPlotSeries = new vector (0.0);
settings->showGrid = true;
settings->gridColor = GetGray(0.1);
settings->xAxisAuto = true;
settings->xAxisTop = false;
settings->xAxisBottom = false;
settings->yAxisAuto = true;
settings->yAxisLeft = false;
settings->yAxisRight = false;
return settings;
}
ScatterPlotSeries *GetDefaultScatterPlotSeriesSettings(){
ScatterPlotSeries *series;
series = new ScatterPlotSeries();
series->linearInterpolation = true;
series->pointType = toVector(L"pixels");
series->lineType = toVector(L"solid");
series->lineThickness = 1.0;
series->xs = new vector (0.0);
series->ys = new vector (0.0);
series->color = GetBlack();
return series;
}
void DrawScatterPlot(RGBABitmapImageReference *canvasReference, double width, double height, vector *xs, vector *ys){
ScatterPlotSettings *settings;
settings = GetDefaultScatterPlotSettings();
settings->width = width;
settings->height = height;
settings->scatterPlotSeries = new vector (1.0);
settings->scatterPlotSeries->at(0) = GetDefaultScatterPlotSeriesSettings();
delete settings->scatterPlotSeries->at(0)->xs;
settings->scatterPlotSeries->at(0)->xs = xs;
delete settings->scatterPlotSeries->at(0)->ys;
settings->scatterPlotSeries->at(0)->ys = ys;
DrawScatterPlotFromSettings(canvasReference, settings);
}
bool DrawScatterPlotFromSettings(RGBABitmapImageReference *canvasReference, ScatterPlotSettings *settings){
double xMin, xMax, yMin, yMax, xLength, yLength, i, x, y, xPrev, yPrev, px, py, pxPrev, pyPrev, originX, originY, p, l, plot;
Rectangle *boundaries;
double xPadding, yPadding, originXPixels, originYPixels;
double xPixelMin, yPixelMin, xPixelMax, yPixelMax, xLengthPixels, yLengthPixels, axisLabelPadding;
NumberReference *nextRectangle, *x1Ref, *y1Ref, *x2Ref, *y2Ref, *patternOffset;
bool prevSet, success;
RGBA *gridLabelColor;
RGBABitmapImage *canvas;
vector *xs, *ys;
bool linearInterpolation;
ScatterPlotSeries *sp;
vector *xGridPositions, *yGridPositions;
StringArrayReference *xLabels, *yLabels;
NumberArrayReference *xLabelPriorities, *yLabelPriorities;
vector *occupied;
vector *linePattern;
bool originXInside, originYInside, textOnLeft, textOnBottom;
double originTextX, originTextY, originTextXPixels, originTextYPixels, side;
canvas = CreateImage(settings->width, settings->height, GetWhite());
patternOffset = CreateNumberReference(0.0);
success = ScatterPlotFromSettingsValid(settings);
if(success){
boundaries = new Rectangle();
ComputeBoundariesBasedOnSettings(settings, boundaries);
xMin = boundaries->x1;
yMin = boundaries->y1;
xMax = boundaries->x2;
yMax = boundaries->y2;
// If zero, set to defaults.
if(xMin - xMax == 0){
xMin = 0;
xMax = 10;
}
if(yMin - yMax == 0){
yMin = 0;
yMax = 10;
}
xLength = xMax - xMin;
yLength = yMax - yMin;
if(settings->autoPadding){
xPadding = floor(GetDefaultPaddingPercentage()*settings->width);
yPadding = floor(GetDefaultPaddingPercentage()*settings->height);
}else{
xPadding = settings->xPadding;
yPadding = settings->yPadding;
}
/* Draw title */
DrawText(canvas, floor(settings->width/2.0 - GetTextWidth(settings->title)/2.0), floor(yPadding/3.0), settings->title, GetBlack());
/* Draw grid */
xPixelMin = xPadding;
yPixelMin = yPadding;
xPixelMax = settings->width - xPadding;
yPixelMax = settings->height - yPadding;
xLengthPixels = xPixelMax - xPixelMin;
yLengthPixels = yPixelMax - yPixelMin;
DrawRectangle1px(canvas, xPixelMin, yPixelMin, xLengthPixels, yLengthPixels, settings->gridColor);
gridLabelColor = GetGray(0.5);
xLabels = new StringArrayReference();
xLabelPriorities = new NumberArrayReference();
yLabels = new StringArrayReference();
yLabelPriorities = new NumberArrayReference();
xGridPositions = ComputeGridLinePositions(xMin, xMax, xLabels, xLabelPriorities);
yGridPositions = ComputeGridLinePositions(yMin, yMax, yLabels, yLabelPriorities);
if(settings->showGrid){
/* X-grid */
for(i = 0.0; i < xGridPositions->size(); i = i + 1.0){
x = xGridPositions->at(i);
px = MapXCoordinate(x, xMin, xMax, xPixelMin, xPixelMax);
DrawLine1px(canvas, px, yPixelMin, px, yPixelMax, settings->gridColor);
}
/* Y-grid */
for(i = 0.0; i < yGridPositions->size(); i = i + 1.0){
y = yGridPositions->at(i);
py = MapYCoordinate(y, yMin, yMax, yPixelMin, yPixelMax);
DrawLine1px(canvas, xPixelMin, py, xPixelMax, py, settings->gridColor);
}
}
/* Compute origin information. */
originYInside = yMin < 0.0 && yMax > 0.0;
originY = 0.0;
if(settings->xAxisAuto){
if(originYInside){
originY = 0.0;
}else{
originY = yMin;
}
}else{
if(settings->xAxisTop){
originY = yMax;
}
if(settings->xAxisBottom){
originY = yMin;
}
}
originYPixels = MapYCoordinate(originY, yMin, yMax, yPixelMin, yPixelMax);
originXInside = xMin < 0.0 && xMax > 0.0;
originX = 0.0;
if(settings->yAxisAuto){
if(originXInside){
originX = 0.0;
}else{
originX = xMin;
}
}else{
if(settings->yAxisLeft){
originX = xMin;
}
if(settings->yAxisRight){
originX = xMax;
}
}
originXPixels = MapXCoordinate(originX, xMin, xMax, xPixelMin, xPixelMax);
if(originYInside){
originTextY = 0.0;
}else{
originTextY = yMin + yLength/2.0;
}
originTextYPixels = MapYCoordinate(originTextY, yMin, yMax, yPixelMin, yPixelMax);
if(originXInside){
originTextX = 0.0;
}else{
originTextX = xMin + xLength/2.0;
}
originTextXPixels = MapXCoordinate(originTextX, xMin, xMax, xPixelMin, xPixelMax);
/* Labels */
occupied = new vector (xLabels->stringArray->size() + yLabels->stringArray->size());
for(i = 0.0; i < occupied->size(); i = i + 1.0){
occupied->at(i) = CreateRectangle(0.0, 0.0, 0.0, 0.0);
}
nextRectangle = CreateNumberReference(0.0);
/* x labels */
for(i = 1.0; i <= 5.0; i = i + 1.0){
textOnBottom = true;
if( !settings->xAxisAuto && settings->xAxisTop){
textOnBottom = false;
}
DrawXLabelsForPriority(i, xMin, originYPixels, xMax, xPixelMin, xPixelMax, nextRectangle, gridLabelColor, canvas, xGridPositions, xLabels, xLabelPriorities, occupied, textOnBottom);
}
/* y labels */
for(i = 1.0; i <= 5.0; i = i + 1.0){
textOnLeft = true;
if( !settings->yAxisAuto && settings->yAxisRight){
textOnLeft = false;
}
DrawYLabelsForPriority(i, yMin, originXPixels, yMax, yPixelMin, yPixelMax, nextRectangle, gridLabelColor, canvas, yGridPositions, yLabels, yLabelPriorities, occupied, textOnLeft);
}
/* Draw origin line axis titles. */
axisLabelPadding = 20.0;
/* x origin line */
if(originYInside){
DrawLine1px(canvas, Round(xPixelMin), Round(originYPixels), Round(xPixelMax), Round(originYPixels), GetBlack());
}
/* y origin line */
if(originXInside){
DrawLine1px(canvas, Round(originXPixels), Round(yPixelMin), Round(originXPixels), Round(yPixelMax), GetBlack());
}
/* Draw origin axis titles. */
DrawTextUpwards(canvas, 10.0, floor(originTextYPixels - GetTextWidth(settings->yLabel)/2.0), settings->yLabel, GetBlack());
DrawText(canvas, floor(originTextXPixels - GetTextWidth(settings->xLabel)/2.0), yPixelMax + axisLabelPadding, settings->xLabel, GetBlack());
/* X-grid-markers */
for(i = 0.0; i < xGridPositions->size(); i = i + 1.0){
x = xGridPositions->at(i);
px = MapXCoordinate(x, xMin, xMax, xPixelMin, xPixelMax);
p = xLabelPriorities->numberArray->at(i);
l = 1.0;
if(p == 1.0){
l = 8.0;
}else if(p == 2.0){
l = 3.0;
}
side = -1.0;
if( !settings->xAxisAuto && settings->xAxisTop){
side = 1.0;
}
DrawLine1px(canvas, px, originYPixels, px, originYPixels + side*l, GetBlack());
}
/* Y-grid-markers */
for(i = 0.0; i < yGridPositions->size(); i = i + 1.0){
y = yGridPositions->at(i);
py = MapYCoordinate(y, yMin, yMax, yPixelMin, yPixelMax);
p = yLabelPriorities->numberArray->at(i);
l = 1.0;
if(p == 1.0){
l = 8.0;
}else if(p == 2.0){
l = 3.0;
}
side = 1.0;
if( !settings->yAxisAuto && settings->yAxisRight){
side = -1.0;
}
DrawLine1px(canvas, originXPixels, py, originXPixels + side*l, py, GetBlack());
}
/* Draw points */
for(plot = 0.0; plot < settings->scatterPlotSeries->size(); plot = plot + 1.0){
sp = settings->scatterPlotSeries->at(plot);
xs = sp->xs;
ys = sp->ys;
linearInterpolation = sp->linearInterpolation;
x1Ref = new NumberReference();
y1Ref = new NumberReference();
x2Ref = new NumberReference();
y2Ref = new NumberReference();
if(linearInterpolation){
prevSet = false;
xPrev = 0.0;
yPrev = 0.0;
for(i = 0.0; i < xs->size(); i = i + 1.0){
x = xs->at(i);
y = ys->at(i);
if(prevSet){
x1Ref->numberValue = xPrev;
y1Ref->numberValue = yPrev;
x2Ref->numberValue = x;
y2Ref->numberValue = y;
success = CropLineWithinBoundary(x1Ref, y1Ref, x2Ref, y2Ref, xMin, xMax, yMin, yMax);
if(success){
pxPrev = floor(MapXCoordinate(x1Ref->numberValue, xMin, xMax, xPixelMin, xPixelMax));
pyPrev = floor(MapYCoordinate(y1Ref->numberValue, yMin, yMax, yPixelMin, yPixelMax));
px = floor(MapXCoordinate(x2Ref->numberValue, xMin, xMax, xPixelMin, xPixelMax));
py = floor(MapYCoordinate(y2Ref->numberValue, yMin, yMax, yPixelMin, yPixelMax));
if(aStringsEqual(sp->lineType, toVector(L"solid")) && sp->lineThickness == 1.0){
DrawLine1px(canvas, pxPrev, pyPrev, px, py, sp->color);
}else if(aStringsEqual(sp->lineType, toVector(L"solid"))){
DrawLine(canvas, pxPrev, pyPrev, px, py, sp->lineThickness, sp->color);
}else if(aStringsEqual(sp->lineType, toVector(L"dashed"))){
linePattern = GetLinePattern1();
DrawLineBresenhamsAlgorithmThickPatterned(canvas, pxPrev, pyPrev, px, py, sp->lineThickness, linePattern, patternOffset, sp->color);
}else if(aStringsEqual(sp->lineType, toVector(L"dotted"))){
linePattern = GetLinePattern2();
DrawLineBresenhamsAlgorithmThickPatterned(canvas, pxPrev, pyPrev, px, py, sp->lineThickness, linePattern, patternOffset, sp->color);
}else if(aStringsEqual(sp->lineType, toVector(L"dotdash"))){
linePattern = GetLinePattern3();
DrawLineBresenhamsAlgorithmThickPatterned(canvas, pxPrev, pyPrev, px, py, sp->lineThickness, linePattern, patternOffset, sp->color);
}else if(aStringsEqual(sp->lineType, toVector(L"longdash"))){
linePattern = GetLinePattern4();
DrawLineBresenhamsAlgorithmThickPatterned(canvas, pxPrev, pyPrev, px, py, sp->lineThickness, linePattern, patternOffset, sp->color);
}else if(aStringsEqual(sp->lineType, toVector(L"twodash"))){
linePattern = GetLinePattern5();
DrawLineBresenhamsAlgorithmThickPatterned(canvas, pxPrev, pyPrev, px, py, sp->lineThickness, linePattern, patternOffset, sp->color);
}
}
}
prevSet = true;
xPrev = x;
yPrev = y;
}
}else{
for(i = 0.0; i < xs->size(); i = i + 1.0){
x = xs->at(i);
y = ys->at(i);
if(x > xMin && x < xMax && y > yMin && y < yMax){
x = floor(MapXCoordinate(x, xMin, xMax, xPixelMin, xPixelMax));
y = floor(MapYCoordinate(y, yMin, yMax, yPixelMin, yPixelMax));
if(aStringsEqual(sp->pointType, toVector(L"crosses"))){
DrawPixel(canvas, x, y, sp->color);
DrawPixel(canvas, x + 1.0, y, sp->color);
DrawPixel(canvas, x + 2.0, y, sp->color);
DrawPixel(canvas, x - 1.0, y, sp->color);
DrawPixel(canvas, x - 2.0, y, sp->color);
DrawPixel(canvas, x, y + 1.0, sp->color);
DrawPixel(canvas, x, y + 2.0, sp->color);
DrawPixel(canvas, x, y - 1.0, sp->color);
DrawPixel(canvas, x, y - 2.0, sp->color);
}else if(aStringsEqual(sp->pointType, toVector(L"circles"))){
DrawCircle(canvas, x, y, 3.0, sp->color);
}else if(aStringsEqual(sp->pointType, toVector(L"dots"))){
DrawFilledCircle(canvas, x, y, 3.0, sp->color);
}else if(aStringsEqual(sp->pointType, toVector(L"triangles"))){
DrawTriangle(canvas, x, y, 3.0, sp->color);
}else if(aStringsEqual(sp->pointType, toVector(L"filled triangles"))){
DrawFilledTriangle(canvas, x, y, 3.0, sp->color);
}else if(aStringsEqual(sp->pointType, toVector(L"pixels"))){
DrawPixel(canvas, x, y, sp->color);
}
}
}
}
}
DeleteImage(canvasReference->image);
canvasReference->image = canvas;
}
return success;
}
void ComputeBoundariesBasedOnSettings(ScatterPlotSettings *settings, Rectangle *boundaries){
ScatterPlotSeries *sp;
double plot, xMin, xMax, yMin, yMax;
if(settings->scatterPlotSeries->size() >= 1.0){
xMin = GetMinimum(settings->scatterPlotSeries->at(0)->xs);
xMax = GetMaximum(settings->scatterPlotSeries->at(0)->xs);
yMin = GetMinimum(settings->scatterPlotSeries->at(0)->ys);
yMax = GetMaximum(settings->scatterPlotSeries->at(0)->ys);
}else{
xMin = -10.0;
xMax = 10.0;
yMin = -10.0;
yMax = 10.0;
}
if( !settings->autoBoundaries ){
xMin = settings->xMin;
xMax = settings->xMax;
yMin = settings->yMin;
yMax = settings->yMax;
}else{
for(plot = 1.0; plot < settings->scatterPlotSeries->size(); plot = plot + 1.0){
sp = settings->scatterPlotSeries->at(plot);
xMin = fmin(xMin, GetMinimum(sp->xs));
xMax = fmax(xMax, GetMaximum(sp->xs));
yMin = fmin(yMin, GetMinimum(sp->ys));
yMax = fmax(yMax, GetMaximum(sp->ys));
}
}
boundaries->x1 = xMin;
boundaries->y1 = yMin;
boundaries->x2 = xMax;
boundaries->y2 = yMax;
}
bool ScatterPlotFromSettingsValid(ScatterPlotSettings *settings){
bool success, found;
ScatterPlotSeries *series;
double i;
success = true;
/* Check axis placement. */
if( !settings->xAxisAuto ){
if(settings->xAxisTop && settings->xAxisBottom){
success = false;
}
if( !settings->xAxisTop && !settings->xAxisBottom ){
success = false;
}
}
if( !settings->yAxisAuto ){
if(settings->yAxisLeft && settings->yAxisRight){
success = false;
}
if( !settings->yAxisLeft && !settings->yAxisRight ){
success = false;
}
}
/* Check series lengths. */
for(i = 0.0; i < settings->scatterPlotSeries->size(); i = i + 1.0){
series = settings->scatterPlotSeries->at(i);
if(series->xs->size() != series->ys->size()){
success = false;
}
if(series->xs->size() == 0.0){
success = false;
}
if(series->linearInterpolation && series->xs->size() == 1.0){
success = false;
}
}
/* Check bounds. */
if( !settings->autoBoundaries ){
if(settings->xMin >= settings->xMax){
success = false;
}
if(settings->yMin >= settings->yMax){
success = false;
}
}
/* Check padding. */
if( !settings->autoPadding ){
if(2.0*settings->xPadding >= settings->width){
success = false;
}
if(2.0*settings->yPadding >= settings->height){
success = false;
}
}
/* Check width and height. */
if(settings->width < 0.0){
success = false;
}
if(settings->height < 0.0){
success = false;
}
/* Check point types. */
for(i = 0.0; i < settings->scatterPlotSeries->size(); i = i + 1.0){
series = settings->scatterPlotSeries->at(i);
if(series->lineThickness < 0.0){
success = false;
}
if( !series->linearInterpolation ){
/* Point type. */
found = false;
if(aStringsEqual(series->pointType, toVector(L"crosses"))){
found = true;
}else if(aStringsEqual(series->pointType, toVector(L"circles"))){
found = true;
}else if(aStringsEqual(series->pointType, toVector(L"dots"))){
found = true;
}else if(aStringsEqual(series->pointType, toVector(L"triangles"))){
found = true;
}else if(aStringsEqual(series->pointType, toVector(L"filled triangles"))){
found = true;
}else if(aStringsEqual(series->pointType, toVector(L"pixels"))){
found = true;
}
if( !found ){
success = false;
}
}else{
/* Line type. */
found = false;
if(aStringsEqual(series->lineType, toVector(L"solid"))){
found = true;
}else if(aStringsEqual(series->lineType, toVector(L"dashed"))){
found = true;
}else if(aStringsEqual(series->lineType, toVector(L"dotted"))){
found = true;
}else if(aStringsEqual(series->lineType, toVector(L"dotdash"))){
found = true;
}else if(aStringsEqual(series->lineType, toVector(L"longdash"))){
found = true;
}else if(aStringsEqual(series->lineType, toVector(L"twodash"))){
found = true;
}
if( !found ){
success = false;
}
}
}
return success;
}
BarPlotSettings *GetDefaultBarPlotSettings(){
BarPlotSettings *settings;
settings = new BarPlotSettings();
settings->width = 800.0;
settings->height = 600.0;
settings->autoBoundaries = true;
settings->yMax = 0.0;
settings->yMin = 0.0;
settings->autoPadding = true;
settings->xPadding = 0.0;
settings->yPadding = 0.0;
settings->title = toVector(L"");
settings->yLabel = toVector(L"");
settings->barPlotSeries = new vector (0.0);
settings->showGrid = true;
settings->gridColor = GetGray(0.1);
settings->autoColor = true;
settings->grayscaleAutoColor = false;
settings->autoSpacing = true;
settings->groupSeparation = 0.0;
settings->barSeparation = 0.0;
settings->autoLabels = true;
settings->xLabels = new vector (0.0);
/*settings.autoLabels = false;
settings.xLabels = new StringReference [5];
settings.xLabels[0] = CreateStringReference("may 20".toCharArray());
settings.xLabels[1] = CreateStringReference("jun 20".toCharArray());
settings.xLabels[2] = CreateStringReference("jul 20".toCharArray());
settings.xLabels[3] = CreateStringReference("aug 20".toCharArray());
settings.xLabels[4] = CreateStringReference("sep 20".toCharArray()); */
settings->barBorder = false;
return settings;
}
BarPlotSeries *GetDefaultBarPlotSeriesSettings(){
BarPlotSeries *series;
series = new BarPlotSeries();
series->ys = new vector (0.0);
series->color = GetBlack();
return series;
}
RGBABitmapImage *DrawBarPlot(double width, double height, vector *ys){
BarPlotSettings *settings;
RGBABitmapImageReference *canvasReference;
settings = GetDefaultBarPlotSettings();
settings->barPlotSeries = new vector (1.0);
settings->barPlotSeries->at(0) = GetDefaultBarPlotSeriesSettings();
delete settings->barPlotSeries->at(0)->ys;
settings->barPlotSeries->at(0)->ys = ys;
canvasReference = new RGBABitmapImageReference();
settings->width = width;
settings->height = height;
DrawBarPlotFromSettings(canvasReference, settings);
return canvasReference->image;
}
bool DrawBarPlotFromSettings(RGBABitmapImageReference *canvasReference, BarPlotSettings *settings){
double xPadding, yPadding;
double xPixelMin, yPixelMin, yPixelMax, xPixelMax;
double xLengthPixels, yLengthPixels;
double s, n, y, x, w, h, yMin, yMax, b, i, py, yValue;
vector *colors;
vector *ys, *yGridPositions;
double yTop, yBottom, ss, bs, yLength;
double groupSeparation, barSeparation, barWidth, textwidth;
StringArrayReference *yLabels;
NumberArrayReference *yLabelPriorities;
vector *occupied;
NumberReference *nextRectangle;
RGBA *gridLabelColor, *barColor;
vector *label;
bool success;
RGBABitmapImage *canvas;
success = BarPlotSettingsIsValid(settings);
if(success){
canvas = CreateImage(settings->width, settings->height, GetWhite());
ss = settings->barPlotSeries->size();
gridLabelColor = GetGray(0.5);
/* padding */
if(settings->autoPadding){
xPadding = floor(GetDefaultPaddingPercentage()*ImageWidth(canvas));
yPadding = floor(GetDefaultPaddingPercentage()*ImageHeight(canvas));
}else{
xPadding = settings->xPadding;
yPadding = settings->yPadding;
}
/* Draw title */
DrawText(canvas, floor(ImageWidth(canvas)/2.0 - GetTextWidth(settings->title)/2.0), floor(yPadding/3.0), settings->title, GetBlack());
DrawTextUpwards(canvas, 10.0, floor(ImageHeight(canvas)/2.0 - GetTextWidth(settings->yLabel)/2.0), settings->yLabel, GetBlack());
/* min and max */
if(settings->autoBoundaries){
if(ss >= 1.0){
yMax = GetMaximum(settings->barPlotSeries->at(0)->ys);
yMin = fmin(0.0, GetMinimum(settings->barPlotSeries->at(0)->ys));
for(s = 0.0; s < ss; s = s + 1.0){
yMax = fmax(yMax, GetMaximum(settings->barPlotSeries->at(s)->ys));
yMin = fmin(yMin, GetMinimum(settings->barPlotSeries->at(s)->ys));
}
}else{
yMax = 10.0;
yMin = 0.0;
}
}else{
yMin = settings->yMin;
yMax = settings->yMax;
}
yLength = yMax - yMin;
/* boundaries */
xPixelMin = xPadding;
yPixelMin = yPadding;
xPixelMax = ImageWidth(canvas) - xPadding;
yPixelMax = ImageHeight(canvas) - yPadding;
xLengthPixels = xPixelMax - xPixelMin;
yLengthPixels = yPixelMax - yPixelMin;
/* Draw boundary. */
DrawRectangle1px(canvas, xPixelMin, yPixelMin, xLengthPixels, yLengthPixels, settings->gridColor);
/* Draw grid lines. */
yLabels = new StringArrayReference();
yLabelPriorities = new NumberArrayReference();
yGridPositions = ComputeGridLinePositions(yMin, yMax, yLabels, yLabelPriorities);
if(settings->showGrid){
/* Y-grid */
for(i = 0.0; i < yGridPositions->size(); i = i + 1.0){
y = yGridPositions->at(i);
py = MapYCoordinate(y, yMin, yMax, yPixelMin, yPixelMax);
DrawLine1px(canvas, xPixelMin, py, xPixelMax, py, settings->gridColor);
}
}
/* Draw origin. */
if(yMin < 0.0 && yMax > 0.0){
py = MapYCoordinate(0.0, yMin, yMax, yPixelMin, yPixelMax);
DrawLine1px(canvas, xPixelMin, py, xPixelMax, py, settings->gridColor);
}
/* Labels */
occupied = new vector (yLabels->stringArray->size());
for(i = 0.0; i < occupied->size(); i = i + 1.0){
occupied->at(i) = CreateRectangle(0.0, 0.0, 0.0, 0.0);
}
nextRectangle = CreateNumberReference(0.0);
for(i = 1.0; i <= 5.0; i = i + 1.0){
DrawYLabelsForPriority(i, yMin, xPixelMin, yMax, yPixelMin, yPixelMax, nextRectangle, gridLabelColor, canvas, yGridPositions, yLabels, yLabelPriorities, occupied, true);
}
/* Draw bars. */
if(settings->autoColor){
if( !settings->grayscaleAutoColor ){
colors = Get8HighContrastColors();
}else{
colors = new vector (ss);
if(ss > 1.0){
for(i = 0.0; i < ss; i = i + 1.0){
colors->at(i) = GetGray(0.7 - (i/ss)*0.7);
}
}else{
colors->at(0) = GetGray(0.5);
}
}
}else{
colors = new vector (0.0);
}
/* distances */
bs = settings->barPlotSeries->at(0)->ys->size();
if(settings->autoSpacing){
groupSeparation = ImageWidth(canvas)*0.05;
barSeparation = ImageWidth(canvas)*0.005;
}else{
groupSeparation = settings->groupSeparation;
barSeparation = settings->barSeparation;
}
barWidth = (xLengthPixels - groupSeparation*(bs - 1.0) - barSeparation*(bs*(ss - 1.0)))/(bs*ss);
/* Draw bars. */
b = 0.0;
for(n = 0.0; n < bs; n = n + 1.0){
for(s = 0.0; s < ss; s = s + 1.0){
ys = settings->barPlotSeries->at(s)->ys;
yValue = ys->at(n);
yBottom = MapYCoordinate(yValue, yMin, yMax, yPixelMin, yPixelMax);
yTop = MapYCoordinate(0.0, yMin, yMax, yPixelMin, yPixelMax);
x = xPixelMin + n*(groupSeparation + ss*barWidth) + s*(barWidth) + b*barSeparation;
w = barWidth;
if(yValue >= 0.0){
y = yBottom;
h = yTop - y;
}else{
y = yTop;
h = yBottom - yTop;
}
/* Cut at boundaries. */
if(y < yPixelMin && y + h > yPixelMax){
y = yPixelMin;
h = yPixelMax - yPixelMin;
}else if(y < yPixelMin){
y = yPixelMin;
if(yValue >= 0.0){
h = yTop - y;
}else{
h = yBottom - y;
}
}else if(y + h > yPixelMax){
h = yPixelMax - y;
}
/* Get color */
if(settings->autoColor){
barColor = colors->at(s);
}else{
barColor = settings->barPlotSeries->at(s)->color;
}
/* Draw */
if(settings->barBorder){
DrawFilledRectangleWithBorder(canvas, Round(x), Round(y), Round(w), Round(h), GetBlack(), barColor);
}else{
DrawFilledRectangle(canvas, Round(x), Round(y), Round(w), Round(h), barColor);
}
b = b + 1.0;
}
b = b - 1.0;
}
/* x-labels */
for(n = 0.0; n < bs; n = n + 1.0){
if(settings->autoLabels){
label = CreateStringDecimalFromNumber(n + 1.0);
}else{
label = settings->xLabels->at(n)->string;
}
textwidth = GetTextWidth(label);
x = xPixelMin + (n + 0.5)*(ss*barWidth + (ss - 1.0)*barSeparation) + n*groupSeparation - textwidth/2.0;
DrawText(canvas, floor(x), ImageHeight(canvas) - yPadding + 20.0, label, gridLabelColor);
b = b + 1.0;
}
canvasReference->image = canvas;
}
return success;
}
bool BarPlotSettingsIsValid(BarPlotSettings *settings){
bool success, lengthSet;
BarPlotSeries *series;
double i, width, height, length;
success = true;
/* Check series lengths. */
lengthSet = false;
length = 0.0;
for(i = 0.0; i < settings->barPlotSeries->size(); i = i + 1.0){
series = settings->barPlotSeries->at(i);
if( !lengthSet ){
length = series->ys->size();
lengthSet = true;
}else if(length != series->ys->size()){
success = false;
}
}
/* Check bounds. */
if( !settings->autoBoundaries ){
if(settings->yMin >= settings->yMax){
success = false;
}
}
/* Check padding. */
if( !settings->autoPadding ){
if(2.0*settings->xPadding >= settings->width){
success = false;
}
if(2.0*settings->yPadding >= settings->height){
success = false;
}
}
/* Check width and height. */
if(settings->width < 0.0){
success = false;
}
if(settings->height < 0.0){
success = false;
}
/* Check spacing */
if( !settings->autoSpacing ){
if(settings->groupSeparation < 0.0){
success = false;
}
if(settings->barSeparation < 0.0){
success = false;
}
}
return success;
}
double GetMinimum(vector *data){
double i, minimum;
minimum = data->at(0);
for(i = 0.0; i < data->size(); i = i + 1.0){
minimum = fmin(minimum, data->at(i));
}
return minimum;
}
double GetMaximum(vector *data){
double i, maximum;
maximum = data->at(0);
for(i = 0.0; i < data->size(); i = i + 1.0){
maximum = fmax(maximum, data->at(i));
}
return maximum;
}
double RoundToDigits(double element, double digitsAfterPoint){
return Round(element*pow(10.0, digitsAfterPoint))/pow(10.0, digitsAfterPoint);
}
double test(){
double z;
vector *gridlines;
NumberReference *failures;
StringArrayReference *labels;
NumberArrayReference *labelPriorities;
RGBABitmapImageReference *imageReference;
vector *xs, *ys;
failures = CreateNumberReference(0.0);
imageReference = CreateRGBABitmapImageReference();
labels = new StringArrayReference();
labelPriorities = new NumberArrayReference();
z = 10.0;
gridlines = ComputeGridLinePositions( -z/2.0, z/2.0, labels, labelPriorities);
AssertEquals(gridlines->size(), 11.0, failures);
z = 9.0;
gridlines = ComputeGridLinePositions( -z/2.0, z/2.0, labels, labelPriorities);
AssertEquals(gridlines->size(), 19.0, failures);
z = 8.0;
gridlines = ComputeGridLinePositions( -z/2.0, z/2.0, labels, labelPriorities);
AssertEquals(gridlines->size(), 17.0, failures);
z = 7.0;
gridlines = ComputeGridLinePositions( -z/2.0, z/2.0, labels, labelPriorities);
AssertEquals(gridlines->size(), 15.0, failures);
z = 6.0;
gridlines = ComputeGridLinePositions( -z/2.0, z/2.0, labels, labelPriorities);
AssertEquals(gridlines->size(), 13.0, failures);
z = 5.0;
gridlines = ComputeGridLinePositions( -z/2.0, z/2.0, labels, labelPriorities);
AssertEquals(gridlines->size(), 21.0, failures);
z = 4.0;
gridlines = ComputeGridLinePositions( -z/2.0, z/2.0, labels, labelPriorities);
AssertEquals(gridlines->size(), 17.0, failures);
z = 3.0;
gridlines = ComputeGridLinePositions( -z/2.0, z/2.0, labels, labelPriorities);
AssertEquals(gridlines->size(), 31.0, failures);
z = 2.0;
gridlines = ComputeGridLinePositions( -z/2.0, z/2.0, labels, labelPriorities);
AssertEquals(gridlines->size(), 21.0, failures);
xs = new vector (5.0);
xs->at(0) = -2.0;
xs->at(1) = -1.0;
xs->at(2) = 0.0;
xs->at(3) = 1.0;
xs->at(4) = 2.0;
ys = new vector (5.0);
ys->at(0) = 2.0;
ys->at(1) = -1.0;
ys->at(2) = -2.0;
ys->at(3) = -1.0;
ys->at(4) = 2.0;
DrawScatterPlot(imageReference, 800.0, 600.0, xs, ys);
imageReference->image = DrawBarPlot(800.0, 600.0, ys);
TestMapping(failures);
TestMapping2(failures);
return failures->numberValue;
}
void TestMapping(NumberReference *failures){
ScatterPlotSeries *series;
ScatterPlotSettings *settings;
RGBABitmapImageReference *imageReference;
double x1, y1;
series = GetDefaultScatterPlotSeriesSettings();
series->xs = new vector (5.0);
series->xs->at(0) = -2.0;
series->xs->at(1) = -1.0;
series->xs->at(2) = 0.0;
series->xs->at(3) = 1.0;
series->xs->at(4) = 2.0;
series->ys = new vector (5.0);
series->ys->at(0) = -2.0;
series->ys->at(1) = -1.0;
series->ys->at(2) = -2.0;
series->ys->at(3) = -1.0;
series->ys->at(4) = 2.0;
series->linearInterpolation = true;
series->lineType = toVector(L"dashed");
series->lineThickness = 2.0;
series->color = GetGray(0.3);
settings = GetDefaultScatterPlotSettings();
settings->width = 600.0;
settings->height = 400.0;
settings->autoBoundaries = true;
settings->autoPadding = true;
settings->title = toVector(L"x^2 - 2");
settings->xLabel = toVector(L"X axis");
settings->yLabel = toVector(L"Y axis");
settings->scatterPlotSeries = new vector (1.0);
settings->scatterPlotSeries->at(0) = series;
imageReference = CreateRGBABitmapImageReference();
DrawScatterPlotFromSettings(imageReference, settings);
x1 = MapXCoordinateAutoSettings( -1.0, imageReference->image, series->xs);
y1 = MapYCoordinateAutoSettings( -1.0, imageReference->image, series->ys);
AssertEquals(x1, 180.0, failures);
AssertEquals(y1, 280.0, failures);
}
void TestMapping2(NumberReference *failures){
vector *xs, *ys, *xs2, *ys2;
double i, x, y, w, h, xMin, xMax, yMin, yMax;
RGBABitmapImageReference *canvasReference;
ScatterPlotSettings *settings;
double points;
double x1, y1;
points = 300.0;
w = 600.0*2.0;
h = 300.0*2.0;
xMin = 0.0;
xMax = 150.0;
yMin = 0.0;
yMax = 1.0;
xs = new vector (points);
ys = new vector (points);
xs2 = new vector (points);
ys2 = new vector (points);
for(i = 0.0; i < points; i = i + 1.0){
x = xMin + (xMax - xMin)/(points - 1.0)*i;
/* points - 1d is to ensure both extremeties are included. */
y = x/(x + 7.0);
xs->at(i) = x;
ys->at(i) = y;
y = 1.4*x/(x + 7.0)*(1.0 - (atan((x/1.5 - 30.0)/5.0)/1.6 + 1.0)/2.0);
xs2->at(i) = x;
ys2->at(i) = y;
}
settings = GetDefaultScatterPlotSettings();
settings->scatterPlotSeries = new vector (2.0);
settings->scatterPlotSeries->at(0) = new ScatterPlotSeries();
settings->scatterPlotSeries->at(0)->xs = xs;
settings->scatterPlotSeries->at(0)->ys = ys;
settings->scatterPlotSeries->at(0)->linearInterpolation = true;
settings->scatterPlotSeries->at(0)->lineType = toVector(L"solid");
settings->scatterPlotSeries->at(0)->lineThickness = 3.0;
settings->scatterPlotSeries->at(0)->color = CreateRGBColor(1.0, 0.0, 0.0);
settings->scatterPlotSeries->at(1) = new ScatterPlotSeries();
settings->scatterPlotSeries->at(1)->xs = xs2;
settings->scatterPlotSeries->at(1)->ys = ys2;
settings->scatterPlotSeries->at(1)->linearInterpolation = true;
settings->scatterPlotSeries->at(1)->lineType = toVector(L"solid");
settings->scatterPlotSeries->at(1)->lineThickness = 3.0;
settings->scatterPlotSeries->at(1)->color = CreateRGBColor(0.0, 0.0, 1.0);
settings->autoBoundaries = false;
settings->xMin = xMin;
settings->xMax = xMax;
settings->yMin = yMin;
settings->yMax = yMax;
settings->yLabel = toVector(L"");
settings->xLabel = toVector(L"Features");
settings->title = toVector(L"");
settings->width = w;
settings->height = h;
canvasReference = CreateRGBABitmapImageReference();
DrawScatterPlotFromSettings(canvasReference, settings);
x1 = MapXCoordinateBasedOnSettings(27.0, settings);
y1 = MapYCoordinateBasedOnSettings(1.0, settings);
AssertEquals(floor(x1), 292.0, failures);
AssertEquals(y1, 60.0, failures);
}
RGBA *GetBlack(){
RGBA *black;
black = new RGBA();
black->a = 1.0;
black->r = 0.0;
black->g = 0.0;
black->b = 0.0;
return black;
}
RGBA *GetWhite(){
RGBA *white;
white = new RGBA();
white->a = 1.0;
white->r = 1.0;
white->g = 1.0;
white->b = 1.0;
return white;
}
RGBA *GetTransparent(){
RGBA *transparent;
transparent = new RGBA();
transparent->a = 0.0;
transparent->r = 0.0;
transparent->g = 0.0;
transparent->b = 0.0;
return transparent;
}
RGBA *GetGray(double percentage){
RGBA *black;
black = new RGBA();
black->a = 1.0;
black->r = 1.0 - percentage;
black->g = 1.0 - percentage;
black->b = 1.0 - percentage;
return black;
}
RGBA *CreateRGBColor(double r, double g, double b){
RGBA *color;
color = new RGBA();
color->a = 1.0;
color->r = r;
color->g = g;
color->b = b;
return color;
}
RGBA *CreateRGBAColor(double r, double g, double b, double a){
RGBA *color;
color = new RGBA();
color->a = a;
color->r = r;
color->g = g;
color->b = b;
return color;
}
RGBABitmapImage *CreateImage(double w, double h, RGBA *color){
RGBABitmapImage *image;
double i, j;
image = new RGBABitmapImage();
image->x = new vector (w);
for(i = 0.0; i < w; i = i + 1.0){
image->x->at(i) = new RGBABitmap();
image->x->at(i)->y = new vector (h);
for(j = 0.0; j < h; j = j + 1.0){
image->x->at(i)->y->at(j) = new RGBA();
SetPixel(image, i, j, color);
}
}
return image;
}
void DeleteImage(RGBABitmapImage *image){
double i, j, w, h;
w = ImageWidth(image);
h = ImageHeight(image);
for(i = 0.0; i < w; i = i + 1.0){
for(j = 0.0; j < h; j = j + 1.0){
delete image->x->at(i)->y->at(j);
}
delete image->x->at(i);
}
delete image;
}
double ImageWidth(RGBABitmapImage *image){
return image->x->size();
}
double ImageHeight(RGBABitmapImage *image){
double height;
if(ImageWidth(image) == 0.0){
height = 0.0;
}else{
height = image->x->at(0)->y->size();
}
return height;
}
void SetPixel(RGBABitmapImage *image, double x, double y, RGBA *color){
if(x >= 0.0 && x < ImageWidth(image) && y >= 0.0 && y < ImageHeight(image)){
image->x->at(x)->y->at(y)->a = color->a;
image->x->at(x)->y->at(y)->r = color->r;
image->x->at(x)->y->at(y)->g = color->g;
image->x->at(x)->y->at(y)->b = color->b;
}
}
void DrawPixel(RGBABitmapImage *image, double x, double y, RGBA *color){
double ra, ga, ba, aa;
double rb, gb, bb, ab;
double ro, go, bo, ao;
if(x >= 0.0 && x < ImageWidth(image) && y >= 0.0 && y < ImageHeight(image)){
ra = color->r;
ga = color->g;
ba = color->b;
aa = color->a;
rb = image->x->at(x)->y->at(y)->r;
gb = image->x->at(x)->y->at(y)->g;
bb = image->x->at(x)->y->at(y)->b;
ab = image->x->at(x)->y->at(y)->a;
ao = CombineAlpha(aa, ab);
ro = AlphaBlend(ra, aa, rb, ab, ao);
go = AlphaBlend(ga, aa, gb, ab, ao);
bo = AlphaBlend(ba, aa, bb, ab, ao);
image->x->at(x)->y->at(y)->r = ro;
image->x->at(x)->y->at(y)->g = go;
image->x->at(x)->y->at(y)->b = bo;
image->x->at(x)->y->at(y)->a = ao;
}
}
double CombineAlpha(double as, double ad){
return as + ad*(1.0 - as);
}
double AlphaBlend(double cs, double as, double cd, double ad, double ao){
return (cs*as + cd*ad*(1.0 - as))/ao;
}
void DrawHorizontalLine1px(RGBABitmapImage *image, double x, double y, double length, RGBA *color){
double i;
for(i = 0.0; i < length; i = i + 1.0){
DrawPixel(image, x + i, y, color);
}
}
void DrawVerticalLine1px(RGBABitmapImage *image, double x, double y, double height, RGBA *color){
double i;
for(i = 0.0; i < height; i = i + 1.0){
DrawPixel(image, x, y + i, color);
}
}
void DrawRectangle1px(RGBABitmapImage *image, double x, double y, double width, double height, RGBA *color){
DrawHorizontalLine1px(image, x, y, width + 1.0, color);
DrawVerticalLine1px(image, x, y + 1.0, height + 1.0 - 1.0, color);
DrawVerticalLine1px(image, x + width, y + 1.0, height + 1.0 - 1.0, color);
DrawHorizontalLine1px(image, x + 1.0, y + height, width + 1.0 - 2.0, color);
}
void DrawImageOnImage(RGBABitmapImage *dst, RGBABitmapImage *src, double topx, double topy){
double y, x;
for(y = 0.0; y < ImageHeight(src); y = y + 1.0){
for(x = 0.0; x < ImageWidth(src); x = x + 1.0){
if(topx + x >= 0.0 && topx + x < ImageWidth(dst) && topy + y >= 0.0 && topy + y < ImageHeight(dst)){
DrawPixel(dst, topx + x, topy + y, src->x->at(x)->y->at(y));
}
}
}
}
void DrawLine1px(RGBABitmapImage *image, double x0, double y0, double x1, double y1, RGBA *color){
XiaolinWusLineAlgorithm(image, x0, y0, x1, y1, color);
}
void XiaolinWusLineAlgorithm(RGBABitmapImage *image, double x0, double y0, double x1, double y1, RGBA *color){
bool steep;
double x, t, dx, dy, g, xEnd, yEnd, xGap, xpxl1, ypxl1, intery, xpxl2, ypxl2, olda;
olda = color->a;
steep = abs(y1 - y0) > abs(x1 - x0);
if(steep){
t = x0;
x0 = y0;
y0 = t;
t = x1;
x1 = y1;
y1 = t;
}
if(x0 > x1){
t = x0;
x0 = x1;
x1 = t;
t = y0;
y0 = y1;
y1 = t;
}
dx = x1 - x0;
dy = y1 - y0;
g = dy/dx;
if(dx == 0.0){
g = 1.0;
}
xEnd = Round(x0);
yEnd = y0 + g*(xEnd - x0);
xGap = OneMinusFractionalPart(x0 + 0.5);
xpxl1 = xEnd;
ypxl1 = floor(yEnd);
if(steep){
DrawPixel(image, ypxl1, xpxl1, SetBrightness(color, OneMinusFractionalPart(yEnd)*xGap));
DrawPixel(image, ypxl1 + 1.0, xpxl1, SetBrightness(color, FractionalPart(yEnd)*xGap));
}else{
DrawPixel(image, xpxl1, ypxl1, SetBrightness(color, OneMinusFractionalPart(yEnd)*xGap));
DrawPixel(image, xpxl1, ypxl1 + 1.0, SetBrightness(color, FractionalPart(yEnd)*xGap));
}
intery = yEnd + g;
xEnd = Round(x1);
yEnd = y1 + g*(xEnd - x1);
xGap = FractionalPart(x1 + 0.5);
xpxl2 = xEnd;
ypxl2 = floor(yEnd);
if(steep){
DrawPixel(image, ypxl2, xpxl2, SetBrightness(color, OneMinusFractionalPart(yEnd)*xGap));
DrawPixel(image, ypxl2 + 1.0, xpxl2, SetBrightness(color, FractionalPart(yEnd)*xGap));
}else{
DrawPixel(image, xpxl2, ypxl2, SetBrightness(color, OneMinusFractionalPart(yEnd)*xGap));
DrawPixel(image, xpxl2, ypxl2 + 1.0, SetBrightness(color, FractionalPart(yEnd)*xGap));
}
if(steep){
for(x = xpxl1 + 1.0; x <= xpxl2 - 1.0; x = x + 1.0){
DrawPixel(image, floor(intery), x, SetBrightness(color, OneMinusFractionalPart(intery)));
DrawPixel(image, floor(intery) + 1.0, x, SetBrightness(color, FractionalPart(intery)));
intery = intery + g;
}
}else{
for(x = xpxl1 + 1.0; x <= xpxl2 - 1.0; x = x + 1.0){
DrawPixel(image, x, floor(intery), SetBrightness(color, OneMinusFractionalPart(intery)));
DrawPixel(image, x, floor(intery) + 1.0, SetBrightness(color, FractionalPart(intery)));
intery = intery + g;
}
}
color->a = olda;
}
double OneMinusFractionalPart(double x){
return 1.0 - FractionalPart(x);
}
double FractionalPart(double x){
return x - floor(x);
}
RGBA *SetBrightness(RGBA *color, double newBrightness){
color->a = newBrightness;
return color;
}
void DrawQuadraticBezierCurve(RGBABitmapImage *image, double x0, double y0, double cx, double cy, double x1, double y1, RGBA *color){
double t, dt, dx, dy;
NumberReference *xs, *ys, *xe, *ye;
dx = abs(x0 - x1);
dy = abs(y0 - y1);
dt = 1.0/sqrt(pow(dx, 2.0) + pow(dy, 2.0));
xs = new NumberReference();
ys = new NumberReference();
xe = new NumberReference();
ye = new NumberReference();
QuadraticBezierPoint(x0, y0, cx, cy, x1, y1, 0.0, xs, ys);
for(t = dt; t <= 1.0; t = t + dt){
QuadraticBezierPoint(x0, y0, cx, cy, x1, y1, t, xe, ye);
DrawLine1px(image, xs->numberValue, ys->numberValue, xe->numberValue, ye->numberValue, color);
xs->numberValue = xe->numberValue;
ys->numberValue = ye->numberValue;
}
delete xs;
delete ys;
delete xe;
delete ye;
}
void QuadraticBezierPoint(double x0, double y0, double cx, double cy, double x1, double y1, double t, NumberReference *x, NumberReference *y){
x->numberValue = pow(1.0 - t, 2.0)*x0 + (1.0 - t)*2.0*t*cx + pow(t, 2.0)*x1;
y->numberValue = pow(1.0 - t, 2.0)*y0 + (1.0 - t)*2.0*t*cy + pow(t, 2.0)*y1;
}
void DrawCubicBezierCurve(RGBABitmapImage *image, double x0, double y0, double c0x, double c0y, double c1x, double c1y, double x1, double y1, RGBA *color){
double t, dt, dx, dy;
NumberReference *xs, *ys, *xe, *ye;
dx = abs(x0 - x1);
dy = abs(y0 - y1);
dt = 1.0/sqrt(pow(dx, 2.0) + pow(dy, 2.0));
xs = new NumberReference();
ys = new NumberReference();
xe = new NumberReference();
ye = new NumberReference();
CubicBezierPoint(x0, y0, c0x, c0y, c1x, c1y, x1, y1, 0.0, xs, ys);
for(t = dt; t <= 1.0; t = t + dt){
CubicBezierPoint(x0, y0, c0x, c0y, c1x, c1y, x1, y1, t, xe, ye);
DrawLine1px(image, xs->numberValue, ys->numberValue, xe->numberValue, ye->numberValue, color);
xs->numberValue = xe->numberValue;
ys->numberValue = ye->numberValue;
}
delete xs;
delete ys;
delete xe;
delete ye;
}
void CubicBezierPoint(double x0, double y0, double c0x, double c0y, double c1x, double c1y, double x1, double y1, double t, NumberReference *x, NumberReference *y){
x->numberValue = pow(1.0 - t, 3.0)*x0 + pow(1.0 - t, 2.0)*3.0*t*c0x + (1.0 - t)*3.0*pow(t, 2.0)*c1x + pow(t, 3.0)*x1;
y->numberValue = pow(1.0 - t, 3.0)*y0 + pow(1.0 - t, 2.0)*3.0*t*c0y + (1.0 - t)*3.0*pow(t, 2.0)*c1y + pow(t, 3.0)*y1;
}
RGBABitmapImage *CopyImage(RGBABitmapImage *image){
RGBABitmapImage *copy;
double i, j;
copy = CreateImage(ImageWidth(image), ImageHeight(image), GetTransparent());
for(i = 0.0; i < ImageWidth(image); i = i + 1.0){
for(j = 0.0; j < ImageHeight(image); j = j + 1.0){
SetPixel(copy, i, j, image->x->at(i)->y->at(j));
}
}
return copy;
}
RGBA *GetImagePixel(RGBABitmapImage *image, double x, double y){
return image->x->at(x)->y->at(y);
}
void HorizontalFlip(RGBABitmapImage *img){
double y, x;
double tmp;
RGBA *c1, *c2;
for(y = 0.0; y < ImageHeight(img); y = y + 1.0){
for(x = 0.0; x < ImageWidth(img)/2.0; x = x + 1.0){
c1 = img->x->at(x)->y->at(y);
c2 = img->x->at(ImageWidth(img) - 1.0 - x)->y->at(y);
tmp = c1->a;
c1->a = c2->a;
c2->a = tmp;
tmp = c1->r;
c1->r = c2->r;
c2->r = tmp;
tmp = c1->g;
c1->g = c2->g;
c2->g = tmp;
tmp = c1->b;
c1->b = c2->b;
c2->b = tmp;
}
}
}
void DrawFilledRectangle(RGBABitmapImage *image, double x, double y, double w, double h, RGBA *color){
double i, j;
for(i = 0.0; i < w; i = i + 1.0){
for(j = 0.0; j < h; j = j + 1.0){
SetPixel(image, x + i, y + j, color);
}
}
}
RGBABitmapImage *RotateAntiClockwise90Degrees(RGBABitmapImage *image){
RGBABitmapImage *rotated;
double x, y;
rotated = CreateImage(ImageHeight(image), ImageWidth(image), GetBlack());
for(y = 0.0; y < ImageHeight(image); y = y + 1.0){
for(x = 0.0; x < ImageWidth(image); x = x + 1.0){
SetPixel(rotated, y, ImageWidth(image) - 1.0 - x, GetImagePixel(image, x, y));
}
}
return rotated;
}
void DrawCircle(RGBABitmapImage *canvas, double xCenter, double yCenter, double radius, RGBA *color){
DrawCircleBasicAlgorithm(canvas, xCenter, yCenter, radius, color);
}
void BresenhamsCircleDrawingAlgorithm(RGBABitmapImage *canvas, double xCenter, double yCenter, double radius, RGBA *color){
double x, y, delta;
y = radius;
x = 0.0;
delta = 3.0 - 2.0*radius;
for(; y >= x; x = x + 1.0){
DrawLine1px(canvas, xCenter + x, yCenter + y, xCenter + x, yCenter + y, color);
DrawLine1px(canvas, xCenter + x, yCenter - y, xCenter + x, yCenter - y, color);
DrawLine1px(canvas, xCenter - x, yCenter + y, xCenter - x, yCenter + y, color);
DrawLine1px(canvas, xCenter - x, yCenter - y, xCenter - x, yCenter - y, color);
DrawLine1px(canvas, xCenter - y, yCenter + x, xCenter - y, yCenter + x, color);
DrawLine1px(canvas, xCenter - y, yCenter - x, xCenter - y, yCenter - x, color);
DrawLine1px(canvas, xCenter + y, yCenter + x, xCenter + y, yCenter + x, color);
DrawLine1px(canvas, xCenter + y, yCenter - x, xCenter + y, yCenter - x, color);
if(delta < 0.0){
delta = delta + 4.0*x + 6.0;
}else{
delta = delta + 4.0*(x - y) + 10.0;
y = y - 1.0;
}
}
}
void DrawCircleMidpointAlgorithm(RGBABitmapImage *canvas, double xCenter, double yCenter, double radius, RGBA *color){
double d, x, y;
d = floor((5.0 - radius*4.0)/4.0);
x = 0.0;
y = radius;
for(; x <= y; x = x + 1.0){
DrawPixel(canvas, xCenter + x, yCenter + y, color);
DrawPixel(canvas, xCenter + x, yCenter - y, color);
DrawPixel(canvas, xCenter - x, yCenter + y, color);
DrawPixel(canvas, xCenter - x, yCenter - y, color);
DrawPixel(canvas, xCenter + y, yCenter + x, color);
DrawPixel(canvas, xCenter + y, yCenter - x, color);
DrawPixel(canvas, xCenter - y, yCenter + x, color);
DrawPixel(canvas, xCenter - y, yCenter - x, color);
if(d < 0.0){
d = d + 2.0*x + 1.0;
}else{
d = d + 2.0*(x - y) + 1.0;
y = y - 1.0;
}
}
}
void DrawCircleBasicAlgorithm(RGBABitmapImage *canvas, double xCenter, double yCenter, double radius, RGBA *color){
double pixels, a, da, dx, dy;
/* Place the circle in the center of the pixel. */
xCenter = floor(xCenter) + 0.5;
yCenter = floor(yCenter) + 0.5;
pixels = 2.0*M_PI*radius;
/* Below a radius of 10 pixels, over-compensate to get a smoother circle. */
if(radius < 10.0){
pixels = pixels*10.0;
}
da = 2.0*M_PI/pixels;
for(a = 0.0; a < 2.0*M_PI; a = a + da){
dx = cos(a)*radius;
dy = sin(a)*radius;
/* Floor to get the pixel coordinate. */
DrawPixel(canvas, floor(xCenter + dx), floor(yCenter + dy), color);
}
}
void DrawFilledCircle(RGBABitmapImage *canvas, double x, double y, double r, RGBA *color){
DrawFilledCircleBasicAlgorithm(canvas, x, y, r, color);
}
void DrawFilledCircleMidpointAlgorithm(RGBABitmapImage *canvas, double xCenter, double yCenter, double radius, RGBA *color){
double d, x, y;
d = floor((5.0 - radius*4.0)/4.0);
x = 0.0;
y = radius;
for(; x <= y; x = x + 1.0){
DrawLineBresenhamsAlgorithm(canvas, xCenter + x, yCenter + y, xCenter - x, yCenter + y, color);
DrawLineBresenhamsAlgorithm(canvas, xCenter + x, yCenter - y, xCenter - x, yCenter - y, color);
DrawLineBresenhamsAlgorithm(canvas, xCenter + y, yCenter + x, xCenter - y, yCenter + x, color);
DrawLineBresenhamsAlgorithm(canvas, xCenter + y, yCenter - x, xCenter - y, yCenter - x, color);
if(d < 0.0){
d = d + 2.0*x + 1.0;
}else{
d = d + 2.0*(x - y) + 1.0;
y = y - 1.0;
}
}
}
void DrawFilledCircleBasicAlgorithm(RGBABitmapImage *canvas, double xCenter, double yCenter, double radius, RGBA *color){
double pixels, a, da, dx, dy;
/* Place the circle in the center of the pixel. */
xCenter = floor(xCenter) + 0.5;
yCenter = floor(yCenter) + 0.5;
pixels = 2.0*M_PI*radius;
/* Below a radius of 10 pixels, over-compensate to get a smoother circle. */
if(radius < 10.0){
pixels = pixels*10.0;
}
da = 2.0*M_PI/pixels;
/* Draw lines for a half-circle to fill an entire circle. */
for(a = 0.0; a < M_PI; a = a + da){
dx = cos(a)*radius;
dy = sin(a)*radius;
/* Floor to get the pixel coordinate. */
DrawVerticalLine1px(canvas, floor(xCenter - dx), floor(yCenter - dy), floor(2.0*dy) + 1.0, color);
}
}
void DrawTriangle(RGBABitmapImage *canvas, double xCenter, double yCenter, double height, RGBA *color){
double x1, y1, x2, y2, x3, y3;
x1 = floor(xCenter + 0.5);
y1 = floor(floor(yCenter + 0.5) - height);
x2 = x1 - 2.0*height*tan(M_PI/6.0);
y2 = floor(y1 + 2.0*height);
x3 = x1 + 2.0*height*tan(M_PI/6.0);
y3 = floor(y1 + 2.0*height);
DrawLine1px(canvas, x1, y1, x2, y2, color);
DrawLine1px(canvas, x1, y1, x3, y3, color);
DrawLine1px(canvas, x2, y2, x3, y3, color);
}
void DrawFilledTriangle(RGBABitmapImage *canvas, double xCenter, double yCenter, double height, RGBA *color){
double i, offset, x1, y1;
x1 = floor(xCenter + 0.5);
y1 = floor(floor(yCenter + 0.5) - height);
for(i = 0.0; i <= 2.0*height; i = i + 1.0){
offset = floor(i*tan(M_PI/6.0));
DrawHorizontalLine1px(canvas, x1 - offset, y1 + i, 2.0*offset, color);
}
}
void DrawLine(RGBABitmapImage *canvas, double x1, double y1, double x2, double y2, double thickness, RGBA *color){
DrawLineBresenhamsAlgorithmThick(canvas, x1, y1, x2, y2, thickness, color);
}
void DrawLineBresenhamsAlgorithmThick(RGBABitmapImage *canvas, double x1, double y1, double x2, double y2, double thickness, RGBA *color){
double x, y, dx, dy, incX, incY, pdx, pdy, es, el, err, t, r;
dx = x2 - x1;
dy = y2 - y1;
incX = Sign(dx);
incY = Sign(dy);
dx = abs(dx);
dy = abs(dy);
if(dx > dy){
pdx = incX;
pdy = 0.0;
es = dy;
el = dx;
}else{
pdx = 0.0;
pdy = incY;
es = dx;
el = dy;
}
x = x1;
y = y1;
err = el/2.0;
if(thickness >= 3.0){
r = thickness/2.0;
DrawCircle(canvas, x, y, r, color);
}else if(floor(thickness) == 2.0){
DrawFilledRectangle(canvas, x, y, 2.0, 2.0, color);
}else if(floor(thickness) == 1.0){
DrawPixel(canvas, x, y, color);
}
for(t = 0.0; t < el; t = t + 1.0){
err = err - es;
if(err < 0.0){
err = err + el;
x = x + incX;
y = y + incY;
}else{
x = x + pdx;
y = y + pdy;
}
if(thickness >= 3.0){
r = thickness/2.0;
DrawCircle(canvas, x, y, r, color);
}else if(floor(thickness) == 2.0){
DrawFilledRectangle(canvas, x, y, 2.0, 2.0, color);
}else if(floor(thickness) == 1.0){
DrawPixel(canvas, x, y, color);
}
}
}
void DrawLineBresenhamsAlgorithm(RGBABitmapImage *canvas, double x1, double y1, double x2, double y2, RGBA *color){
double x, y, dx, dy, incX, incY, pdx, pdy, es, el, err, t;
dx = x2 - x1;
dy = y2 - y1;
incX = Sign(dx);
incY = Sign(dy);
dx = abs(dx);
dy = abs(dy);
if(dx > dy){
pdx = incX;
pdy = 0.0;
es = dy;
el = dx;
}else{
pdx = 0.0;
pdy = incY;
es = dx;
el = dy;
}
x = x1;
y = y1;
err = el/2.0;
DrawPixel(canvas, x, y, color);
for(t = 0.0; t < el; t = t + 1.0){
err = err - es;
if(err < 0.0){
err = err + el;
x = x + incX;
y = y + incY;
}else{
x = x + pdx;
y = y + pdy;
}
DrawPixel(canvas, x, y, color);
}
}
void DrawLineBresenhamsAlgorithmThickPatterned(RGBABitmapImage *canvas, double x1, double y1, double x2, double y2, double thickness, vector *pattern, NumberReference *offset, RGBA *color){
double x, y, dx, dy, incX, incY, pdx, pdy, es, el, err, t, r;
dx = x2 - x1;
dy = y2 - y1;
incX = Sign(dx);
incY = Sign(dy);
dx = abs(dx);
dy = abs(dy);
if(dx > dy){
pdx = incX;
pdy = 0.0;
es = dy;
el = dx;
}else{
pdx = 0.0;
pdy = incY;
es = dx;
el = dy;
}
x = x1;
y = y1;
err = el/2.0;
offset->numberValue = fmod(offset->numberValue + 1.0, pattern->size()*thickness);
if(pattern->at(floor(offset->numberValue/thickness))){
if(thickness >= 3.0){
r = thickness/2.0;
DrawCircle(canvas, x, y, r, color);
}else if(floor(thickness) == 2.0){
DrawFilledRectangle(canvas, x, y, 2.0, 2.0, color);
}else if(floor(thickness) == 1.0){
DrawPixel(canvas, x, y, color);
}
}
for(t = 0.0; t < el; t = t + 1.0){
err = err - es;
if(err < 0.0){
err = err + el;
x = x + incX;
y = y + incY;
}else{
x = x + pdx;
y = y + pdy;
}
offset->numberValue = fmod(offset->numberValue + 1.0, pattern->size()*thickness);
if(pattern->at(floor(offset->numberValue/thickness))){
if(thickness >= 3.0){
r = thickness/2.0;
DrawCircle(canvas, x, y, r, color);
}else if(floor(thickness) == 2.0){
DrawFilledRectangle(canvas, x, y, 2.0, 2.0, color);
}else if(floor(thickness) == 1...