Skip to content
Joshua Wade edited this page Jun 5, 2018 · 6 revisions

VectorGraph

image

Overview

This widget is a graph. It is currently implemented in the Waveshaper 2 plugin, but there are many more potential applications that could be realized with minimal modification to the graph code.

Unlike the current automation system, points cannot replace other points or move past them. This provides for a system that is much easier to use effectively.

Design

The graph stores a set of points, each with a float value for their x and y positions on the graph. Currently the values must be from 0 to 1. For some applications it may be useful to change this.

CalculateSample(input) is used to get the y value of the graph at a given x value. The input and output are both 0 to 1 values.

The adding and removing of points on the graph is taken care of internally by the user interface. It is however possible to do this from the outside as well as to completely replace the points inside with a new set.

Points can be retrieved using myModel.getPoint(index) and can have their internal state modified. You can change their tension values and curve types, and prevent them from moving in either the x or y directions by using lockX() and lockY().

myModel.tryMove(index, x, y) attempts to move a point to a new location. If the requested location is too far in either the x or the y direction, the point will be moved as far as possible.

The graph currently complies with the new UI and is based on the waveshaper design.

The tension value for a connection between two points is always stored in the point after. The first point's tension value isn't used.

Methods

If you don't see a method here, it might be inherited from the QWidget class. If there is something missing, please add it!


float VectorGraph::calculateSample(float input);

Calls float VectorGraphModel::calculateSample(float input);.


VectorGraphPoint * VectorGraphModel::getPoint(int index);

Returns a pointer to the point specified by the given index. This just gets the element at index in the QVector that stores the points.


int VectorGraphModel::getSectionStartIndex(float input);

Gets the closest point to the left of your input. For example, if there are points at 0, 0.2, 0.8 and 1.0 and the input is 0.5, then the output will be 1, because 0.2 is the closest number to the left of 0.5.


float VectorGraphModel::calculateSectionSample(float input, int sectionStartIndex);

Used internally, but documented here in case someone needs to modify it.

The graph delegates its processing into sections. Take the following graph:

A graph divided into three sections

This graph is divided into three sections. The way this is processed is most easily explained by example. Say your x value input is on the first gridline. If you follow the grid up to the graph line and then over to the left, you'll see that the corresponding y value is 5 grid lines up.

Here's how the value is calculated: calculateSample scales and shifts the input so that all the inputs between the left and right points of the section fall between 0 and 1. So for our example, the input would be multiplied by about 3, since the section takes up 1/3 of the full width of the graph. The input would not be shifted since it already starts at 0. If the input was in the second section, it would need to be shifted left (in the negative direction) before it was multiplied. Once the input is shifted, calculateSample passes it along to calculateSectionSample along with the index of the start point for that section.

calculateSectionSample treats its section as if it were a whole graph. This simplifies the math immensely. The math is the same, regardless of where the start and end points are. The only variables are the tension, the tension type, and the scaled input value.

The output is scaled in a similar way, but in reverse this time. Because our graph section takes up about half of the full output window, the result from calculateSectionSample must be multiplied by 1/2 to get it between 0 and 1/2. If the desired output range didn't start at 0, then we would also have to shift the output up (in the positive direction). Section 2 is another example where this would be necessary.


float VectorGraphModel::calculateSample(float input);

Takes a 0 to 1 x input and calculates the corresponding y output. See calcualteSectionSample above for a more detailed explanation.


void VectorGraphModel::insertPointAfter(int index, VectorGraphPoint point);

Inserts the given point after the given index. This method ignores the rules about where a point can go, so use caution! This is meant to be used with getSectionStartIndex.


void VectorGraphModel::tryMove(int index, float x, float y);

Moves the point at the given index to a new location, if possible. If the requested location is out of bounds or will cause the points to be out of order, the point will be moved as far as it can go without going out of bounds.


int VectorGraphModel::getPointIndexFromCoords(int x, int y, int canvasWidth, int canvasHeight);

Gets the index of a point from the given coordinates. The coordinates must within the circle drawn for the point as defined by getPointSize(), a method defined in the header which returns a hard-coded value.


int VectorGraphModel::getPointIndexFromTensionHandleCoords(int x, int y, int canvasWidth, int canvasHeight);

Gets the index of the point after a tension handle given by the coordinates. The coordinates must within the circle drawn for the tension handle as defined by getTensionHandleSize(), a method defined in the header which returns a hard-coded value.


void VectorGraphModel::deletePoint(int index);

Deletes the point at the given index.


void VectorGraphModel::setTensionTypeOnPoint(int index, VectorGraph::TensionType type)

Sets the tension type of a point. A point's tension type will affect the line before it.


void VectorGraphPoint::lockX();
void VectorGraphPoint::lockY();
void VectorGraphPoint::unlockX();
void VectorGraphPoint::unlockY();

Locks or unlocks the point. Intended for key modifiers. Use permaLock and permaUnlock for anything that shouldn't be able to move at all.