*Andrey Ruzhanskiy*

##
**Generel things**

A line chart is a diagram representing a certain change between arbitrary units. Generally, it consists of two interval scaled axis. The important concept behind this diagram is to show a certain change in respect to units and in respect to (maybe) other datasets. It is not intended to show absolute measurements.

##
**Axisscalings**

Due to the fact that a line diagram represents change, it should concentrate to show it without deliberate bias. Therefore, the minimum tickmark on each axis should be set according to the minima of the dataset (or on the global minima of all datasets that are to be represented). It is not useful to set the coordinate origin to (0|0), neither as to any other point other than the global minima. Another trivial concept which has to be followed is the fact that the maxima of the datasets should also be represented on the diagram.
The *LineChartRasterizer* currently uses the min and the max of the datasets to set the ticks accordingly. The output and the resolution highly depend on the choosen scalings, therefore other concepts should be applicable, as long as the do not falsify the representation.

##
**Axis**

There is not much to say about the axis itself, the *LineChartRasterizer* does not use an arrow head to show continuity of the datasets because there is none. It ends with tha max value on the x axis which was present on the dataset. As for the tickmarksize, the *LineChartRasterizer* currently uses 2.

##
**Line rasterizing algorithm**

The *LineChartRasterizer* currently uses the **bresenham** algorithm to draw a line between two datapoints as nearly to the ideal line as possible. Because **bresenham** assumes an equal distant grid, there is a conversion to be done between the geometrical position (for example in milimetres) and the dot position, measured in braillecell/ dots. The current implementation looksup the nearest point, which is why there are sometime aritfact points.

There is also the issue that on the canvas, the y coordinates grow bigger as they go down, but bresenham assumes that the origin of the y coordinates is in the left bottom corner.

Here the code:

```
private void bresenham(final Double xStart, final Double yStart, final Double xEnd, final Double yEnd) {
int y0 = (int) (mCanvas.toDotRectangle(mCellLineArea).intWrapper().getHeight() - yStart); // Conversion of the origin
int y1 = (int) (mCanvas.toDotRectangle(mCellLineArea).intWrapper().getHeight() - yEnd); // Conversion of the origin
int x0 = (int) (xStart.doubleValue());
int x1 = (int) (xEnd.doubleValue());
int dx = abs(x1 - x0);
int dy = -abs(y1 - y0);
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx + dy;
int e2;
while (true) {
mCanvas.getCurrentPage().setValue((int) (mCanvas.toDotRectangle(mCellLineArea).getHeight() - y0), (int) x0, true);
if (x0 == x1 && y0 == y1) {
break;
}
e2 = 2 * err;
if (e2 > dy) {
err += dy;
x0 += sx;
}
if (e2 < dx) {
err += dx;
y0 += sy;
}
}
}
```

There is future work to be done in evaluating more line draw algorithms, for example "P. Stephenson, B. Litow: Running the line:Line drawing using runs and runs of runs". Sadly, this algorithm is closed source and was only made available after the project finished.

##
**Point rasterizing algorithm**

To draw a line, one need a method to draw point. This is also done via a conversion between a geometrical view to a "braille" view. Here the code:

```
private SimplePointListImpl rasterizePoints(final PointList list, final double globalMinX, final double globalMinY) {
Objects.requireNonNull(list, "The given PointList for the rasterization of points was null!");
double xMin = globalMinX;
double yMin = globalMinY;
Iterator<Point2DDouble> iter = list.getListIterator();
Rectangle canvas = mCanvas.toDotRectangle(mCellLineArea);
double canvasStartX = canvas.intWrapper().getX();
double canvasStartY = canvas.intWrapper().getBottom();
SimplePointListImpl result = new SimplePointListImpl();
while (iter.hasNext()) { // iterate through all datapoints
Point2DDouble current = iter.next();
double currentValueX = current.getX() - xMin;
double currentValueY = current.getY() - yMin;
double stepX = currentValueX / mDpiX;
double stepY = currentValueY / mDpiY;
result.pushBack(new Point2DDouble(round(canvasStartX + mXStepWidth * mCanvas.getCellWidth() * stepX), round(canvasStartY - mYStepWidth * mCanvas.getCellHeight() * stepY)));
mCanvas.getCurrentPage().setValue((int) round(canvasStartY - mYStepWidth * mCanvas.getCellHeight() * stepY), (int) round(canvasStartX + mXStepWidth * mCanvas.getCellWidth() * stepX), true);
}
result.calculateExtrema();
return result;
}
```