Exploring Analyic Geometry with Mathematica®

Home Contents Commands Packages Explorations Reference
Tour Lines Circles Conics Analysis Tangents

Biarcs

Biarc Carrier Circles
Knot Point
Knot Circles
Biarc Programming Examples
Explorations

In this chapter we will demonstrate some techniques for adding new functions to Descarta2D. To make the demonstration realistic, we will introduce the mathematics for a new type of tangent circle construction called a biarc. Biarcs are used in some graphical computer systems to connect a set of data points with smoothly joined arcs. The mathematics of biarcs is by itself interesting and will serve as a good example of extending the capabilities of Descarta2D.

Initialize

To initialize Descarta2D, select the input cell bracket and press SHIFT-Enter.

This initialization assumes that the Descarta2D software has been copied into one of the standard directories for AddOns which are on the Mathematica search path, $Path.

<<Descarta2D`

Biarc Carrier Circles [Top]

A biarc is a composite curve consisting of two circular arcs, placed end to end with continuity of slope at the join point. The two circles underlying the arc are called the biarc carrier circles. The carrier circles may be internally or externally tangent to each other, and the point of tangency that joins the two arcs is called the knot point of the biarc. Referring to Figure [biarc:fig01], suppose we wish to construct a smooth curve between points "biarc_1.gif" and "biarc_2.gif" such that the tangents to the curve at "biarc_3.gif" and "biarc_4.gif" are the unit vectors "biarc_5.gif" and "biarc_6.gif". "biarc_7.gif", "biarc_8.gif", "biarc_9.gif" and "biarc_10.gif" are called the biarc configuration parameters.

"biarc_11.gif"

Biarc configuration parameters.

The geometric condition that two circles are tangent can always be expressed as

sum or difference of radii=distance between the centers

according to the kind of contact, external (sum of radii) or internal (difference of radii).

We take positive values of "biarc_12.gif" and "biarc_13.gif" to indicate that the center points of the carrier circles, "biarc_14.gif" and "biarc_15.gif", are offset in the direction of "biarc_16.gif" and "biarc_17.gif", respectively. "biarc_18.gif" and "biarc_19.gif" are unit vectors constructed by rotating tangent vectors "biarc_20.gif" and "biarc_21.gif" "biarc_22.gif" counter-clockwise. Suppose we now wish to form an expression for the left-hand side of Equation ([biarc:eqn01]). It can be shown that the expressions "biarc_23.gif" and "biarc_24.gif" represent all cases for the sum (squared) and difference (squared) of the biarc radii for all combinations of positive or negative "biarc_25.gif" and "biarc_26.gif" for both internally and externally tangent carrier circles.

We introduce a radius sign constant, "biarc_27.gif", which may take on the values ±1, in order to accommodate internally or externally tangent carrier circles in the same equation,

"biarc_28.gif"

Note that it makes no difference whether we associate "biarc_29.gif" with "biarc_30.gif" or "biarc_31.gif", since after squaring and applying "biarc_32.gif", the relationship is symmetric,

"biarc_33.gif"

The carrier circle center points, "biarc_34.gif" and "biarc_35.gif", may be written as

"biarc_36.gif" = "biarc_37.gif"
"biarc_38.gif" = "biarc_39.gif"

Combining Equations ([biarc:eqn02]) and ([biarc:eqn03]) as suggested by Equation ([biarc:eqn01]), the sum or difference of the radii (squared) equals the distance (squared) between "biarc_40.gif" and "biarc_41.gif", yields

"biarc_42.gif"

When simplifying Equation ([biarc:eqn04]), note that the relationships "biarc_43.gif" and "biarc_44.gif" can be used, since "biarc_45.gif" and "biarc_46.gif" are defined as unit vectors. Rearranging Equation ([biarc:eqn04]) and using the following substitutions

"biarc_47.gif" = "biarc_48.gif"
"biarc_49.gif" = "biarc_50.gif"
"biarc_51.gif" = "biarc_52.gif"
"biarc_53.gif" = "biarc_54.gif"

produces the equation

"biarc_55.gif"

which establishes the general relationship between the radii, "biarc_56.gif" and "biarc_57.gif", of the carrier circles. Constants "biarc_58.gif", "biarc_59.gif", "biarc_60.gif" and d are referred to as the biarc defining constants. Geometrically, "biarc_61.gif" is the cosine of the angle between the tangent vectors, "biarc_62.gif" is the (signed) distance from "biarc_63.gif" to the line defined by "biarc_64.gif" and "biarc_65.gif", "biarc_66.gif" is the (signed) distance from "biarc_67.gif" to the line defined by "biarc_68.gif" and "biarc_69.gif" and "biarc_70.gif" is the distance (squared) between points "biarc_71.gif" and "biarc_72.gif". Note that these defining constants depend only on the relative position of the defining geometry and are independent of the choice of coordinate axes.

Radii Ratio

If a relationship between the carrier circle radii, "biarc_73.gif" and "biarc_74.gif", is specified, then Equation ([biarc:eqn05]) can be solved for the radii. We choose to specify the biarc radii ratio, "biarc_75.gif", as the defining relationship. Substituting "biarc_76.gif" into Equation ([biarc:eqn05]) produces the equation

"biarc_77.gif"

Solving Equation ([biarc:eqn06]) by using the quadratic formula yields

"biarc_78.gif" = "biarc_79.gif"
"biarc_80.gif" = "biarc_81.gif"

In the special case where the tangent vectors are in the same direction, the denominator "biarc_82.gif" will equal zero, and the quadratic equation degenerates and the solution of the resulting linear equation is

"biarc_83.gif"

Thus, by specifying a biarc radii ratio, κ, and applying Equation ([biarc:eqn07]) or ([biarc:eqn08]) we may calculate values for "biarc_84.gif" and "biarc_85.gif". Equation ([biarc:eqn03]) allows us to calculate the corresponding coordinates of the carrier circle centers, "biarc_86.gif" and "biarc_87.gif". In certain configurations only one arc is needed to satisfy the position and tangent constraints. In this case, the equations will produce centers and radii for two identical circles.

Number of Solutions

Given a specific pair of points, "biarc_88.gif" and "biarc_89.gif" and tangent vectors, "biarc_90.gif" and "biarc_91.gif", we now consider how many different carrier circle pairs exist for a given radii ratio, κ. The solutions may be enumerated as follows:

• Equations ([biarc:eqn07]) or ([biarc:eqn08]) may produce negative values for "biarc_92.gif" or "biarc_93.gif". The sign indicates the directions the center points "biarc_94.gif" and "biarc_95.gif" should be offset from "biarc_96.gif" and "biarc_97.gif", respectively. As a result, both κ and may produce valid biarcs with a specified radii ratio.

• The radius sign constant, "biarc_98.gif", may take on two different values, ±1.

• The quadratic formula yields two different solutions due to the sign preceding the radical sign as shown in Equation ([biarc:eqn07]).

Therefore, as many as 2×2×2=8 unique carrier circle pairs may exist for a given biarc configuration and radii ratio.

Knot Point [Top]

Suppose we wish to compute the coordinates of the knot point, "biarc_99.gif", which is the point of tangency between the two carrier circles. The coordinates of the knot point can be found by intersecting the two circles and taking advantage of the fact that they intersect in a single point yielding

"biarc_100.gif" = "biarc_101.gif"
"biarc_102.gif" = "biarc_103.gif"

where

"biarc_104.gif" = "biarc_105.gif"
R = "biarc_106.gif"

While it is a simple matter to compute the knot point once we have the two carrier circles, we might instead want to specify the position of the knot point. We will show in this section that the knot point cannot be selected arbitrarily, but must lie on one of two specific circles, called the knot circles. The following theorem and corollary from elementary geometry (which are stated without proof) will be central to exploring the nature of the knot circles.

Theorem. Angles at the circumference of a circle subtended by the same arc are equal.

Corollary. Given two fixed points "biarc_107.gif" and "biarc_108.gif" and a variable point Q, the locus of Q is a circle if "biarc_109.gif" is a constant.

"biarc_110.gif"

Knot point angles.

Consider two internally tangent carrier circles centered at "biarc_111.gif" and "biarc_112.gif" and with radii "biarc_113.gif" and "biarc_114.gif", respectively, as shown in Figure [biarc:fig10]. By construction the two circles are internally tangent at the origin. Pick two arbitrary points "biarc_115.gif" and "biarc_116.gif" on the circles with coordinates

"biarc_117.gif"

We will show that the angle "biarc_118.gif" is a constant angle for all such points "biarc_119.gif" and "biarc_120.gif" when the angle ω is constant, and, having established this fact, we will apply the corollary stated above to establish that the knot point must be on one of two circles.

The slopes of lines "biarc_121.gif" and "biarc_122.gif", "biarc_123.gif" and "biarc_124.gif", are given by

"biarc_125.gif" = "biarc_126.gif"
"biarc_127.gif" = "biarc_128.gif"

and the angle, α, between "biarc_129.gif" and "biarc_130.gif" is

tanα = "biarc_131.gif"
. = "biarc_132.gif"
. = "biarc_133.gif"
. = "biarc_134.gif"

The angle ω between the two tangent lines "biarc_135.gif" and "biarc_136.gif" is given by

"biarc_137.gif" = ω (or π-ω)
"biarc_138.gif" = ω (or π-ω)
"biarc_139.gif" = ω (or π-ω).

Notice that since ω is a constant, by definition, for any given biarc configuration, "biarc_140.gif" is also a constant. Since α is a function of "biarc_141.gif" it must also be a constant. Now applying the corollary, the knot point must be on one of two circles corresponding to the two constant values of α. Similar proofs hold for other geometric configurations and also for externally tangent circles.

Knot Circles [Top]

"biarc_142.gif"

Knot circles.

In the previous section it was established that all the valid knot points for a given biarc configuration must lie on either of two circles. These two circles can be constructed geometrically by considering the limiting cases of the carrier circle radii, "biarc_143.gif" and "biarc_144.gif", as shown in Figure [biarc:fig11]. First, notice that the tangency points "biarc_145.gif" and "biarc_146.gif" must be on the knot circles because they correspond to the knot point in the trivial cases when "biarc_147.gif" and "biarc_148.gif". Now imagine a circle anchored at "biarc_149.gif", tangent to line "biarc_150.gif", and increasing in radius from zero. At some value of "biarc_151.gif", the circle will become tangent to line "biarc_152.gif" at the point labeled "biarc_153.gif" (or "biarc_154.gif", if the circle is on the opposite side of "biarc_155.gif"). At this value of "biarc_156.gif", "biarc_157.gif" will be infinite and the second biarc circle will become a line. The three points "biarc_158.gif", "biarc_159.gif" and "biarc_160.gif" determine the first knot circle, and "biarc_161.gif", "biarc_162.gif", and "biarc_163.gif" determine the second knot circle.

Since the construction is symmetrical, we could have increased the radius of the second carrier circle, "biarc_164.gif", from zero and found points "biarc_165.gif" and "biarc_166.gif" which are on the same two knot circles as those defined by "biarc_167.gif" and "biarc_168.gif".

The center points of the knot circles can be constructed by intersecting the perpendicular bisector of "biarc_169.gif" with the angle bisectors of lines "biarc_170.gif" and "biarc_171.gif". Using simple trigonometric relationships it can be shown that the radii of the two knot circles, r' and r'', are given by

"biarc_172.gif"

where d is the distance between "biarc_173.gif" and "biarc_174.gif" and ω is the angle between "biarc_175.gif" and "biarc_176.gif".

Biarc Programming Examples [Top]

Descarta2D does not provide built-in functions for computing biarcs directly, so we will use the facilities available in Descarta2D along with the programming capabilities provided by Mathematica to demonstrate how new functions can be added to Descarta2D. In order to keep the examples simple, we will ignore special cases and possible error conditions. Better implementations would check for special cases and report errors in the input arguments when such errors are detected.

Knot Circles

The first example illustrates a Mathematica function that will return a list of two knot circles given a biarc configuration (tangent points and tangent lines). For simplicity we will use a triangle to define the biarc configuration with the implicit understanding that the first and third vertices of the triangle, "biarc_177.gif" and "biarc_178.gif", are the tangent points, "biarc_179.gif" and "biarc_180.gif", and sides "biarc_181.gif" and "biarc_182.gif" of the triangle are the tangent lines, "biarc_183.gif" and "biarc_184.gif". Using a triangle as an input parameter has the added advantage that many invalid cases are avoided because they would involve invalid triangles.

(*1*) KnotCircles2D[t1:Triangle2D[p1:{x1_,y1_},
(*2*)                             pA:{xA_,yA_},
(*3*)                             p2:{x2_,y2_}]] :=
(*4*) Module[{pt1,pt2},
(*5*)    pt1=Point2D[t1,Inscribed2D];
(*6*)    pt2=Point2D[Point2D[pA],Point2D[p1],
(*7*)                -Distance2D[p2,pA]];
(*8*)    Map[Circle2D[Point2D[p1],Point2D[p2],#]&,
(*9*)        {pt1,pt2}] ];

Lines 1, 2 and 3 define a Mathematica function called KnotCircles2D that takes one parameter that is required to pattern match a Descarta2D triangle object. Line 4 opens a Module statement that defines two local variables pt1 and pt2. Line 5 constructs a point at the center of a circle inscribed in the triangle. Line 6 constructs a point offset from the apex point, pA, to the tangency point, p1, a negative distance defined by p2 and pA. Lines 8 and 9 construct two circles from the two tangency points and a third point, pt1 or pt2.

Example: Construct the two knot circles associated with the triangle whose vertices are (0,0), (2,1) and (3,0). Plot the geometric objects.

Solution: The function KnotCircles2D[triangle], defined above, returns a list of two knot circles associated with a triangle.

t1=Triangle2D[p1=Point2D[{0,0}],
              p2=Point2D[{2,1}],
              p3=Point2D[{3,0}]];
kc=KnotCircles2D[t1] //N

"biarc_185.gif"

Sketch2D[{p1,p2,p3,t1,kc,Point2D[t1,Inscribed2D]}]

"biarc_186.gif"

Descarta2D Hint: In the KnotCircles2D function whose implementation is shown above, the third point on the second knot circle is constructed following the technique described earlier in the chapter. However, the third point of the first knot circle is constructed as the center of the circle inscribed in the triangle. The exploration knotin.html at the end of the chapter shows that this point is actually on the first knot circle. Using this point has the added advantage that it avoids an error condition that would otherwise occur when "biarc_187.gif" and "biarc_188.gif" are equidistant from the third point of the triangle (an isosceles biarc configuration).

Arc Construction

In this section we will implement functions for constructing bulge factor arcs given defining points and tangent vectors. These will be used later to construct biarcs. First, we define a utility function, Cross2D, that computes a vector cross-product in two dimensions.

Cross2D[{u1_,v1_},{u2_,v2_}]:=u1*v2-u2*v1;

Now we define an arc construction function that takes the arc's start and end points, "biarc_189.gif" and "biarc_190.gif", as input, plus a point associated with the start point indicating the direction of the tangent to the arc at the start point. The justification for this function is provided in the exploration arcentry.html.

Arc2D[{Point2D[p0:{x0_,y0_}],Point2D[p:{x_,y_}]},
       Point2D[p1:{x1_,y1_}]]:=
   Module[{v0=p-p0,chd=p1-p0,s,c},
      s=Cross2D[v0,chd];
      c=Dot[v0,chd];
      Arc2D[p0,p1,s/(c+Sqrt[c^2+s^2])] ];

The next arc construction function is similar to the previous one, except the point indicating the tangent direction is associated with the end point of the arc. The justification for this function is provided in the exploration arcexit.html.

Arc2D[Point2D[p0:{x0_,y0_}],
      {Point2D[p1:{x1_,y1_}],Point2D[p:{x_,y_}]}]:=
   Module[{v1=p-p1,chd=p1-p0,s,c},
      s=Cross2D[chd,v1];
      c=Dot[chd,v1];
      Arc2D[p0,p1,s/(c+Sqrt[c^2+s^2])] ];

Knot Points

Now that we have functions for computing knot circles and constructing arcs involving tangent vectors, it is fairly easy to construct biarcs. Consider the following Mathematica function:

(*1*) Biarc2D[t1:Triangle2D[p0:{x0_,y0_},
(*2*)                       pA:{xA_,yA_},
(*3*)                       p1:{x1_,y1_}],
(*4*)         ptK:Point2D[{xk_,yk_}]] :=
(*5*)    {Arc2D[{Point2D[p0],Point2D[pA]},ptK],
(*6*)     Arc2D[{Point2D[p1],Point2D[pA]},ptK]};

The function Biarc2D takes two arguments, a Descarta2D triangle object defining the biarc configuration (lines 1-3), and a Descarta2D point object defining the knot point (line 4). The function Arc2D[{point,point},point], defined in the previous section, is used twice to actually construct the biarc which is returned as a list of two arcs (lines 5-6).

Example: Construct the biarc associated with the triangle whose vertices are (0,0), (2,1) and (3,0) and a knot point on the first knot circle at parameter value π/2. Plot the geometric objects.

Solution: The function Biarc2D[triangle,point] described above returns a list of two arcs (a biarc) given a triangle that defines the biarc configuration and the knot point.

t1=Triangle2D[p1=Point2D[{0,0}],
              p2=Point2D[{2,1}],
              p3=Point2D[{3,0}]];
kc=KnotCircles2D[t1] //N;
bi1=Biarc2D[t1,pk=Point2D[kc[[1]][Pi/2]]] //N

"biarc_191.gif"

Sketch2D[{p1,p2,p3,t1,pk,bi1}]

"biarc_192.gif"

Descarta2D Hint: The Biarc2D function does not check to insure that the knot point provided is a valid knot point. It will erroneously return two arcs that are not tangent to each other if it is called with a point not on one of the knot circles. Other errors will occur if the knot point coincides with one of the triangle vertices.

It would be convenient if the biarc construction function computed the knot point internally as shown in the following Mathematica function:

(*1*) Biarc2D[t1:Triangle2D[p0:{x0_,y0_},
(*2*)                       pA:{xA_,yA_},
(*3*)                       p1:{x1_,y1_}],
(*4*)       knotCircleNumber_Integer,
(*5*)       knotPointParameter_?IsScalar2D] :=
(*6*)   Module[{kc,ptK},
(*7*)      kc=KnotCircles2D[t1][[knotCircleNumber]];
(*8*)      ptK=Point2D[kc[knotPointParameter]] //N;
(*9*)      Biarc2D[t1,ptK] ];

This Biarc2D function takes three arguments, the first being a triangle defining the biarc configuration, the second an integer equal to 1 or 2 specifying which biarc circle the knot point should be on, and the third an angle (in radians) specifying the parameter location on the knot circle for the desired knot point. Lines 1-5 define the function arguments, line 7 computes the knot circle, line 8 computes the knot point, and line 9 computes the biarc.

Example: Construct the biarc associated with the triangle whose vertices are (0,0), (2,1) and (3,0) and a knot point on the first knot circle at parameter value π/2.

Solution: The function

Biarc2D[triangle,knotCircleNumber,knotCircleParameter]

as implemented above returns the required biarc.

t1=Triangle2D[p1=Point2D[{0,0}],
              p2=Point2D[{2,1}],
              p3=Point2D[{3,0}]];
bi1=Biarc2D[t1,1,Pi/2] //N

"biarc_193.gif"

The Biarc2D functions implemented above are restrictive in the sense that the tangent vectors always point toward the apex point of the triangle and no provision is available to allow either (or both) of the tangent vectors to point away from the apex. In order to overcome this restriction we will implement a function that takes two line segments to define the biarc configuration. The line segments will define a position (the start point of the line segment) and a direction (from the start point towards the end point).

(*1*) Biarc2D[Segment2D[p0:{x0_,y0_},d0:{u0_,v0_}],
(*2*)         Segment2D[p1:{x1_,y1_},d1:{u1_,v1_}],
(*3*)         ptK:Point2D[{xk_,yk_}]] :=
(*4*)    {Arc2D[{Point2D[p0],Point2D[d0]},ptK],
(*5*)     Arc2D[ptK,{Point2D[p1],Point2D[d1]}]};

(*1*) Biarc2D[L0:Segment2D[p0:{x0_,y0_},d0:{u0_,v0_}],
(*2*)         L1:Segment2D[p1:{x1_,y1_},d1:{u1_,v1_}],
(*3*)       knotCircleNumber_Integer,
(*4*)       knotCircleParameter_?IsScalar2D] :=
(*5*)   Module[{ptA,t1,kc,ptK},
(*6*)      ptA=Point2D[Line2D[L0],Line2D[L1]];
(*7*)      t1=Triangle2D[p0,Coordinates2D[ptA],p1];
(*8*)      kc=KnotCircles2D[t1][[knotCircleNumber]];
(*9*)      ptK=Point2D[kc[knotCircleParameter]];
(*10*)     Biarc2D[L0,L1,ptK] ];

These Biarc2D functions are parallel implementations of the previous two, except two line segments are used to define the biarc configuration instead of a triangle.

Example: Given a biarc configuration defined by the line segments from (0,0) to (-3,2) and from (3,0) to (4,-2) construct a set of biarcs whose knot points are on knot circle 1 at parameter values π/3, π/2 and 2π/3.

Solution: Use the function Biarc2D whose implementation is provided above.

ls0=Segment2D[{0,0},{-3,2}] //N;
ls1=Segment2D[{3,0},{4,-2}] //N;
bi1=Map[(Biarc2D[ls0,ls1,1,#] //N)&,{Pi/6,Pi/2,5Pi/6}];

Map[(Print[Sketch2D[{ls0,ls1,#}]])&,bi1];

"biarc_194.gif"

"biarc_195.gif"

"biarc_196.gif"

Building on these basic Mathematica programs for computing biarcs, more elaborate construction functions could be provided. For example, we might write a function that attempts to automatically select the knot point based on some minimization criteria; or we might attempt to construct biarcs that have no reversal of curvature at the knot point (i.e. the carrier circles are internally tangent to each other). Another interesting exercise is to devise a strategy for connecting a predefined set of points with a smooth, piecewise curve consisting of biarcs.

Explorations [Top]

Incenter on Knot Circle. [knotin.html]

Show that the incenter of a triangle (the center point of the circle inscribed in the triangle) is on one of the knot circles for the biarc configuration defined by the triangle.


Copyright © 1999-2007 Donald L. Vossler, Descarta2D Publishing
www.Descarta2D.com