Slope Drawing Math

I want to make a little interactive graph where the user can drag a ball up and down in the middle of the graph to change the slope of a curve of a line going from lower-left to upper-right. Like this:

I’m having trouble figuring out the math of how to draw the line. I know the slopes can be super-radical or fairly smooth, I just want a happy medium, it’s just for display anyway. The middle is linear, the lower is gradual slopes, the higher is steeper slopes.

Can anyone help me figure the math out?

The math (based on your diagram) is already built in to XOJO.
Take a look at the CURVESHAPE object. The point depicted by your white dot is the 1st Order Control point of a Cubic Bezier Curve

This looks like an exponential curve on the span [0, 1]. The handle would be at x=0.5 with y ranging also in [0, 1]. Get the exponent by solving x^?=y then plot the curve and handle dot. Also, those example images are like twice as wide as high but the actual plotted space is the [0, 1] unit square.

Thanks for the responses. I got closer with Will’s suggestion, although the equation gets the Steep-to-Linear but not the Linear-to-Gradual. I used a Multiplier of 10 to get that, but then my scale is exponential and not linear. See the graphic below, note the slider is markedly on the left.

I see where you were going Dave, but the curve doesn’t look even close. Below is a graphic with Will’s equation on the left and CurveShape on the right.

The test project is here: Slope Test Any ideas?

This is an interesting problem. I knocked up this simple test app to learn more about how curveshape works:

Simple Curveshape Test

Launch the program, then click around in the window to see how curveshape behaves. I think I could see pretty easily how to make the curve behave the way you intended.

OK, here’s my version of it (in XML so I could work it in REAL2011r3)

Simple Curveshape Test 2

Closer, and okay, but I want to drag a ball, on the curve, in the middle (always Width / 2) to bend the curve. Right my mod drags the curve but the mouse is not dragging the line, it’s just somewhat arbitrary (and note that the curve is not bent enough to at least get close to the top or bottom).

Alright, this is closer (will still need some tweaks):

Simple Curveshape Test 3

I have a Bezier class that may be interesting to you.
Would you like to me to post it?

Brian, yes, please, thanks!

Thanks Kimball, I think I got it going here. Thanks!

If you can wait a couple of days, I’m doing a article on my blog on beziers. The code may be useful. You’ll be abe to create this:

a small demo video to demonstrate what it can do:

Great GREAT example, using Propellerheads Reason - those cables blew everyone away when they came out. I liked your movie, I’m really looking forward to your blogpost - I can wait!

Here you go.
Bezier class

You construct the bezier using four points. Two end points and two control points.
The placement of the control points dictates how the line is drawn.

Here’s a simplish, non-optimized drawing of the curve just to demostrate the parts. For a thicker curve line you may need to offset by half the thickness, at least on mac lines aren’t centered on the coordinates. And it’s plotting a line for every X pixel which makes lots of very short lines that don’t anti-alias well overall. Not sure of the best way to fix that and/or it depends on OS.

Also this isn’t doing any mouse work, I worked up a quick handling of that in this project in MainWindow1.

Setup: Add a Canvas named display locked on all sides. Add a Slider named YSlider on the left or right of the Canvas, locked top, bottom and the side its on with LiveScroll=true, Minimum = 1, Maximum = 999 and Value = 500. Then add these events…

Sub ValueChanged()
End Sub

Sub Paint(g As Graphics, areas() As REALbasic.Rect)
g.ForeColor = &c1D1D1D
g.FillRect 0, 0, g.Width, g.Height

//set defining x, y and calculate exponent so that x^exponent=y
dim x, y, exponent As double

x = 0.5
y = YSlider.Value / 1000
exponent = log(y) / log(x)

//calculate scalings for pixel x into [0, 1] and y in [0, 1] to pixel y
dim lastx, lasty As integer, xscaler, yscaler As double

lastx = g.Width - 1
lasty = g.Height - 1
xscaler = 1 / lastx //scaling down so lastx * xscaler = 1
yscaler = lasty //scaling up so 1 * yscaler = lasty

//plot curve
dim x0, y0, x1, y1 As double

x0 = 0 //set first line coord outside of loop, always bottom left
y0 = lasty

for pixX As integer = 1 to lastx

x = pixX * xscaler            //calc <x, y> in curve coordinates
y = x ^ exponent

x1 = pixX                     //scale to pixel coordinates
y1 = lasty - y * yscaler

g.ForeColor = &c393939        //draw fill drop line
g.DrawLine x1, y1, x1, lasty

g.ForeColor = &cC1861A        //draw curve line
g.DrawLine x0, y0, x1, y1    

x0 = x1                       //roll coords for next line
y0 = y1


//draw handle
y = 0.5 ^ exponent
g.ForeColor = &cFEFFB5
g.FillOval lastx * 0.5 - 5, lasty - y * yscaler - 5, 11, 11

End Sub[/code]

And here’s a class for drawing N-point bezier curves with an optional dash pattern
In the demo you can drag points around or context-click in empty space to add a new control point to the end. Or context-click on a point to delete that point.

Possibly beziers can be used to draw nicer anti-aliased approximations of the exponential curve but I’m not sure how to set the inner control points since they don’t actually lie on the curve. If there is a way and you’re on a mac then NSBezierPath will give the nicest rendering, I think that’s part of MacOSLib now.

Correction, I’ve been calling this an exponential function but it’s actually a power function :slight_smile: