# C# code to derive tangential points between two circles to create a trapezoid

These are the steps to determine coordinates of the 4 points (P1, P2, P3, P4) that make up a tangential trapezoid connecting to circles. Another way of looking at it is to think of the tangential segments of being the parts of a belt that would not be wrapped around the pulleys. The math should work regardless of the orientation of the two circles in coordinate space.

Code (usage @ bottom):

internal class TrapezoidBuilder
{
private const double RadiansToDegrees = 180/Math.PI;

public TrapezoidPoints TrapezoidPoints;

public TrapezoidBuilder(Point pointC0, Point pointC1, double bufferDistanceC0, double bufferDistanceC1)
{
_pointC0 = pointC0;
_pointC1 = pointC1;
_bufferDistanceC0 = bufferDistanceC0;
_bufferDistanceC1 = bufferDistanceC1;

TrapezoidPoints = new TrapezoidPoints();

CalculateTrapezoidPoints();
}

public void CalculateTrapezoidPoints()
{
// Get the angle of the line C0-C1 in degrees. This will be used in conjunction with angleA to determine the vector of these points
double angleRelativeToPositiveXAxis = CalculateAngleRelativeToXAxis(_pointC0, _pointC1);

// Get angleA
double angleA = CalculateAngleA(_pointC0, _pointC1, _bufferDistanceC0, _bufferDistanceC1);

////  Calculate P1 and P2 coordinates first

double positiveAngle = angleRelativeToPositiveXAxis + angleA;

// Set P1's X coordinate

// Set P2's X coordinate

// Set P1's Y coordinate

// Set P2's Y coordinate

////  Calculate P3 and P4 coordinates

double negativeAngle = angleRelativeToPositiveXAxis - angleA;

// Set P4's X coordinate

// Set P3's X coordinate

// Set P4's Y coordinate

// Set P3's Y coordinate

Debug.WriteLine("C0   " + _pointC0.X + "   " + _pointC0.Y);
Debug.WriteLine("C1   " + _pointC1.X + "   " + _pointC1.Y);

Debug.WriteLine("P1   " + TrapezoidPoints.P1.X + "   " + TrapezoidPoints.P1.Y);
Debug.WriteLine("P2   " + TrapezoidPoints.P2.X + "   " + TrapezoidPoints.P2.Y);
Debug.WriteLine("P3   " + TrapezoidPoints.P3.X + "   " + TrapezoidPoints.P3.Y);
Debug.WriteLine("P4   " + TrapezoidPoints.P4.X + "   " + TrapezoidPoints.P4.Y);
}

{
double xDistance = pointC1.X - pointC0.X;
double yDistance = pointC1.Y - pointC0.Y;

double distance = Math.Sqrt((xDistance*xDistance) + (yDistance*yDistance));

return angleAInDegrees;
}

private double CalculateAngleRelativeToXAxis(Point point0, Point point1)
{
try
{
// In order to use ATAN2, point C1 has to be considered as the origin, i.e. 0, 0.
// So C1x is subtracted from C2x and C1y from C2y. Note that it’s important to subtract
// the 1st value from the 2nd to help determine which quadrant the angle is in.
double x = point1.X - point0.X;
double y = point1.Y - point0.Y;

// Get the angle in radians

// Convert to degrees

// Subtract from 90 to get the angle relative to the positive X-axis
double relativeAngleInDegrees = 90 - angleInDegrees;
// Return result
return relativeAngleInDegrees;
}
catch (Exception err)
{
Debug.WriteLine(err.Message);
}

// If no result, return zero
return 0;
}
}

internal class TrapezoidPoints
{
public Point P1;
public Point P2;
public Point P3;
public Point P4;
}

// Usage
Point C1 = new Point(5,7);
Point C2 = new Point(6.516, 7.875);
double buffer0 = 1;
double buffer1 = .375;

var trapezoidBuilder = new TrapezoidBuilder(C1, C2, buffer0, buffer1);

• Great question but pseudo code is off-topic – AD7six May 18 '12 at 10:59
• With all due respect (and I should have read the rules first), this policy isn't helpful. While I'm capable of posting actual code, it will become very specific (harder to wade through), will not provide a concrete example and would result in wasted effort if my general approach is wrong. – Stonetip May 18 '12 at 13:06
• I'm just a member, but pseudo code has one huge disadvantage - you can't check if the code actually works or run it to ensure the changes you proposed would actually work. – AD7six May 18 '12 at 13:23
• This problem is perfect for F#. I would start out by writing out the formulas in LaTeX. – Leonid May 18 '12 at 20:27
• Uhm, what's the question being asked here? – miniBill Jul 11 '12 at 16:12

1. It's not clear to me what are buffer0 and buffer1? If these represent the radius values (like C1-P1 line for buffer1), then perhaps radius0 (and radius1) would be a better name here.
2. I'd create and use a data class for each point-radius pair. Say, InputPoint class with Point and Radius or something similar.
3. I'd separate constructor and results. The results are calculations that should not be part of the constructor. Take, for example, the class named UriBuilder in .NET: you can construct it, change the inputs, and only when you call the property named Uri - you get the calculated uri. The same should apply here, too. Constructing a class gives us an instance with a valid state. Calculations - in their own methods or property-getters (that are practically methods, by the way). So TrapezoidPoints should be the returned type of a GetTrapezoid method (or maybe TryGetTrapezoid if this pattern apply here), and not part of the class' state.