Exploring Analyic Geometry with Mathematica®

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

D2DTriangle2D

The package D2DTriangle2D implements the Triangle2D object.

Initialization

BeginPackage["D2DTriangle2D`",{"D2DCircle2D`", "D2DExpressions2D`", "D2DGeometry2D`", "D2DLine2D`", "D2DMaster2D`", "D2DNumbers2D`", "D2DPoint2D`", "D2DSegment2D`", "D2DSketch2D`", "D2DTransform2D`"}];

D2DTriangle2D::usage=
   "D2DTriangle2D is a package that implements the Triangle2D object.";

Centroid2D::usage=
   "Centroid2D is the keyword required in Point2D[triangle, Centroid2D].";

Circumscribed2D::usage=
   "Circumscribed2D is the keyword required in Circle2D[triangle, Circumscribed2D]; it is also required in Point2D[triangle, Circumscribed2D].";

Inscribed2D::usage=
   "Inscribed2D is the keyword required in Circle2D[triangle, Inscribed2D]; it is also required in Point2D[triangle, Inscribed2D].";

SolveTriangle2D::usage=
   "SolveTriangle2D[{{s1,s2,s3},{a1,a2,a3}}] computes a complete triangle configuration of the form {{s1,s2,s3},{a1,a2,a3}} given three of the six sides and/or angles; unspecified sides and/or angles should be specified as Null; SolveTriangle2D[{{s1,s2,s3},{a1,a2,a3}}, True] computes an alternate configuration, if one exists.";

Triangle2D::usage=
   "Triangle2D[{x1,y1},{x2,y2},{x3,y3}] is the standard form of a triangle, the coordinates being the vertices of the triangle.";

Begin["`Private`"];

Description

Representation

Format: Triangle2D[{"D2DTriangle2D_1.gif","D2DTriangle2D_2.gif"},{"D2DTriangle2D_3.gif","D2DTriangle2D_4.gif"},{"D2DTriangle2D_5.gif","D2DTriangle2D_6.gif"}]
Standard representation of a triangle object in Descarta2D.  The three arguments are the vertex coordinates of the triangle.

Graphics

Provides graphics for a triangle by extending the Mathematica Display command. Executed when the package is loaded.

SetDisplay2D[
   Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],
   Line[{{x1,y1},{x2,y2},{x3,y3},{x1,y1}}] ];

Validation

Format: Triangle2D[{"D2DTriangle2D_7.gif","D2DTriangle2D_8.gif"},{"D2DTriangle2D_9.gif","D2DTriangle2D_10.gif"},{"D2DTriangle2D_11.gif","D2DTriangle2D_12.gif"}]
Detects that the arguments of a triangle are imaginary and returns the $Failed symbol.  If the imaginary parts are insignificant, they are removed.

Triangle2D::imaginary=
   "An invalid triangle of the form 'Triangle2D[`1`, `2`, `3`]' has been detected; the arguments cannot be imaginary.";

Triangle2D[p1:{x1_,y1_},p2:{x2_,y2_},p3:{x3_,y3_}] :=
   (Triangle2D @@
       ChopImaginary2D[Triangle$2D[p1,p2,p3]]) /;
(FreeQ[{p1,p2,p3},_Pattern] && IsTinyImaginary2D[{p1,p2,p3}]);

Triangle2D[p1:{x1_,y1_},p2:{x2_,y2_},p3:{x3_,y3_}] :=
   (Message[Triangle2D::imaginary,p1,p2,p3];$Failed) /;
(FreeQ[{p1,p2,p3},_Pattern] && IsComplex2D[{p1,p2,p3},0]);

Format: Triangle2D[{"D2DTriangle2D_13.gif","D2DTriangle2D_14.gif"},{"D2DTriangle2D_15.gif","D2DTriangle2D_16.gif"},{"D2DTriangle2D_17.gif","D2DTriangle2D_18.gif"}]
Detects that the vertex points of a triangle are collinear and returns the $Failed symbol.

Triangle2D::invalid=
   "An invalid triangle of the form 'Triangle2D[`1`, `2`, `3`]' has detected; the vertex points cannot be collinear.";

Triangle2D[p1:{x1_,y1_},p2:{x2_,y2_},p3:{x3_,y3_}] :=
   (Message[Triangle2D::invalid,{x1,y1},{x2,y2},{x3,y3}];$Failed) /;
(FreeQ[{p1,p2,p3},_Pattern] &&
IsCollinear2D[Point2D[p1],Point2D[p2],Point2D[p3]]);

Format: IsValid2D[triangle]
Verifies that a triangle is valid.

IsValid2D[Triangle2D[
             {x1_?IsScalar2D,y1_?IsScalar2D},
             {x2_?IsScalar2D,y2_?IsScalar2D},
             {x3_?IsScalar2D,y3_?IsScalar2D}]] := True;

Queries

Configuration Query and Check

The private function IsValidConfiguration$2D[{{"D2DTriangle2D_19.gif","D2DTriangle2D_20.gif","D2DTriangle2D_21.gif"},{"D2DTriangle2D_22.gif","D2DTriangle2D_23.gif","D2DTriangle2D_24.gif"}}] checks the validity of a complete triangle configuration and returns True if it is valid; otherwise, returns False.

IsValidConfiguration$2D[{
   S:{s1_?IsScalar2D,s2_?IsScalar2D,s3_?IsScalar2D},
   A:{a1_?IsScalar2D,a2_?IsScalar2D,a3_?IsScalar2D}}]:=True /;
Not[IsZeroOrNegative2D[{s1,s2,s3,a1,a2,a3}]] &&
(IsZero2D[s1*Sin[a2]-s2*Sin[a1]] ||
    Not[IsReal2D[s1*Sin[a2]-s2*Sin[a1]]]) &&
(IsZero2D[s2*Sin[a3]-s3*Sin[a2]] ||
    Not[IsReal2D[s2*Sin[a3]-s3*Sin[a2]]]) &&
(IsZero2D[s1*Sin[a3]-s3*Sin[a1]] ||
    Not[IsReal2D[s1*Sin[a3]-s3*Sin[a1]]]) &&
(IsZero2D[Pi-(a1+a2+a3)] ||
    Not[IsReal2D[Pi-(a1+a2+a3)]]);

IsValidConfiguration$2D[___]:=False;

The private function CheckConfiguration$2D[{{"D2DTriangle2D_25.gif","D2DTriangle2D_26.gif","D2DTriangle2D_27.gif"},{"D2DTriangle2D_28.gif","D2DTriangle2D_29.gif","D2DTriangle2D_30.gif"}}] checks the validity of a complete triangle configuration and returns the configuration unchanged if it is valid; otherwise, reports an error and returns $Failed.

SolveTriangle2D::invConfig=
   "The configuration of sides and/or angles specified is invalid; no triangle can be constructed.";

CheckConfiguration$2D[{
   S:{s1_?IsScalar2D,s2_?IsScalar2D,s3_?IsScalar2D},
   A:{a1_?IsScalar2D,a2_?IsScalar2D,a3_?IsScalar2D}}]:={S,A} /;
IsValidConfiguration$2D[{S,A}];

CheckConfiguration$2D[___]:=
   (Message[SolveTriangle2D::invConfig];$Failed);

Vertex Query

The private function IsVertex$2D[n] returns True if n is a valid triangle vertex number (1, 2 or 3); otherwise, returns False.

IsVertex$2D[n_] := (n==1 || n==2 || n==3);

Scalars

Angle

Format: Angle2D[triangle,n]
Computes the angle at a vertex of a triangle.

Angle2D[Triangle2D[p1:{x1_,y1_},p2:{x2_,y2_},p3:{x3_,y3_}],n_] :=
   Angle2D[Triangle2D[p2,p3,p1],n-1] /;
(n==2 || n==3);

Angle2D[Triangle2D[p1:{x1_,y1_},p2:{x2_,y2_},p3:{x3_,y3_}],n_] :=
   Module[{a,b,c},
      a=Distance2D[p1,p2];
      b=Distance2D[p1,p3];
      c=Distance2D[p2,p3];
      ArcCos[(a^2+b^2-c^2)/(2*a*b)] ] /;
(n==1);

Solve Triangle

Format: SolveTriangle2D[{{"D2DTriangle2D_31.gif","D2DTriangle2D_32.gif","D2DTriangle2D_33.gif"},{"D2DTriangle2D_34.gif","D2DTriangle2D_35.gif","D2DTriangle2D_36.gif"}},(True | False)]
Completely solves a triangle given a partial configuration of side lengths and angles and returns the complete configuration of sides and angles.  Three of the six configuration parameters are expected, and the others should be set to Null.  If more than three configuration parameters are specified, then they must be consistent.  The second argument, when set to True, returns an alternate configuration if two solutions exist; if omitted, it defaults to False.  The global variable is used at lower levels to resolve ambiguous cases.  The private function SolveTriangle$2D must be called three times to fill in up to three missing configuration parameters.

D2D$SolveTriangle2D$AlternateSolution=False;

SolveTriangle2D[{
   S:{s1_?IsScalar2D | Null,s2_?IsScalar2D | Null,s3_?IsScalar2D | Null},
   A:{a1_?IsScalar2D | Null,a2_?IsScalar2D | Null,a3_?IsScalar2D | Null}},
   alternateSolution_:False]:=
   (D2D$SolveTriangle2D$AlternateSolution=alternateSolution;
    CheckConfiguration$2D[Nest[SolveTriangle$2D,{S,A},3]]) /;
MemberQ[{True,False},alternateSolution];

Checks for under-constrained configurations, and, if detected, displays an error message.

SolveTriangle2D::constrain=
   "The triangle configuration is under-constrained; three constraints are expected.";

SolveTriangle2D[{
   S:{s1_?IsScalar2D | Null,s2_?IsScalar2D | Null,s3_?IsScalar2D | Null},
   A:{a1_?IsScalar2D | Null,a2_?IsScalar2D | Null,a3_?IsScalar2D | Null}},
   alternateSolution_:False]:=
   (Message[SolveTriangle2D::constrain];$Failed) /;
(Count[A,Null]>1 && Count[Join[S,A],Null]>3) &&
MemberQ[{True,False},alternateSolution];

Two angles are known, compute the third using "D2DTriangle2D_37.gif".

SolveTriangle$2D[{S:{s1_,s2_,s3_},
                  A:{a1_?IsScalar2D,a2_?IsScalar2D,Null} |
                  A:{a1_?IsScalar2D,Null,a2_?IsScalar2D} |
                  A:{Null,a1_?IsScalar2D,a2_?IsScalar2D}}]:=
   {S,A /. Null->Pi-(a1+a2)};

Three sides are known (SSS), but not all the angles.  Compute the missing angles directly.

SolveTriangle$2D[{S:{s1_?IsScalar2D,s2_?IsScalar2D,s3_?IsScalar2D},
                  A:{a1_,a2_,a3_} /; Count[A,Null]>0}]:=
   {S,{If[a1===Null,ArcCos[(-s1^2+s2^2+s3^2)/(2*s2*s3)],a1],
       If[a2===Null,ArcCos[( s1^2-s2^2+s3^2)/(2*s1*s3)],a2],
       If[a3===Null,ArcCos[( s1^2+s2^2-s3^2)/(2*s1*s2)],a3]}};

Three angles are known (AAA) but no sides.  Compute all the sides directly.  Since this case is under-constrained, we use the added constraint that the perimeter is set equal to 1 and issue a warning message.

SolveTriangle2D::anglesOnly=
   "The triangle configuration is under-constrained; a valid configuration with the triangle's perimeter arbitrarily set to 1 will be computed.";

SolveTriangle$2D[{S:{Null,Null,Null},
                  A:{a1_?IsScalar2D,a2_?IsScalar2D,a3_?IsScalar2D}}]:=
Module[{SA},
   SA={{Sin[a1],Sin[a2],Sin[a3]}/(Sin[a1]+Sin[a2]+Sin[a3]),A};
   If[IsValidTriangleQ$2D[SA],Message[SolveTriangle2D::anglesOnly]];
   SA];

Three angles are known and at least one side.  Compute the missing side(s) using the Law of Sines.

SolveTriangle$2D[{S:{___,_?IsScalar2D,___} /; Count[S,Null]>0,
                  A:{a1_?IsScalar2D,a2_?IsScalar2D,a3_?IsScalar2D}}]:=
Module[{n=1,sides=S},
   While[S[[n]]===Null,n++];
   Map[(If[S[[#]]===Null,sides[[#]]=S[[n]]*Sin[A[[#]]]/Sin[A[[n]]]])&,
       {1,2,3}];
   {sides,A} ];

Two sides and the included angle are known (SAS).  Compute the third side using the Law of Cosines.

SolveTriangle$2D[
   {S:{s1_?IsScalar2D,Null,s3_?IsScalar2D},A:{a1_,a2_?IsScalar2D,a3_}} |
   {S:{Null,s3_?IsScalar2D,s1_?IsScalar2D},A:{a2_?IsScalar2D,a3_,a1_}} |
   {S:{s3_?IsScalar2D,s1_?IsScalar2D,Null},A:{a3_,a1_,a2_?IsScalar2D}} ]:=
{S /. Null->Sqrt[s1^2+s3^2-2*s1*s3*Cos[a2]],A};

Two sides and one angle (not the included angle) are known (SSA-CCW).

SolveTriangle$2D[
   {S:{s1_?IsScalar2D,s2_?IsScalar2D,Null},A:{a1_?IsScalar2D,Null,Null}} |
   {S:{s2_?IsScalar2D,Null,s1_?IsScalar2D},A:{Null,Null,a1_?IsScalar2D}} |
   {S:{Null,s1_?IsScalar2D,s2_?IsScalar2D},A:{Null,a1_?IsScalar2D,Null}}
   ]:=
{S /. Null->SolveTriangle$SSA$2D[{s1,s2,a1}],A};

One angle (not the included angle) and two sides are known (SSA-CW).

SolveTriangle$2D[
   {S:{s1_?IsScalar2D,Null,s3_?IsScalar2D},A:{a1_?IsScalar2D,Null,Null}} |
   {S:{Null,s3_?IsScalar2D,s1_?IsScalar2D},A:{Null,Null,a1_?IsScalar2D}} |
   {S:{s3_?IsScalar2D,s1_?IsScalar2D,Null},A:{Null,a1_?IsScalar2D,Null}}
   ]:=
{S /. Null->SolveTriangle$SSA$2D[{s1,s3,a1}],A};

Special function for solving SSA cases.  Returns the length of the third side of the configuration, or Null if the configuration is invalid.

SolveTriangle2D::ambiguous=
   "Two valid solutions exist for this configuration; set the alternate solution option to '`1`' to compute the other configuration.";

SolveTriangle$SSA$2D[{s1_,s2_,a1_}]:=
Module[{a2,a2alt,a3,a3alt,s3,s3alt,normValid,altValid},
   a2=ArcSin[s2*Sin[a1]/s1];  a2alt=Pi-a2;
   a3=Pi-(a1+a2);             a3alt=Pi-(a1+a2alt);
   s3=Sqrt[s1^2+s2^2-2*s1*s2*Cos[a3]];
   s3alt=Sqrt[s1^2+s2^2-2*s1*s2*Cos[a3alt]];
   normValid=IsValidConfiguration$2D[{{s1,s2,s3},{a1,a2,a3}}];
   altValid=IsValidConfiguration$2D[{{s1,s2,s3alt},{a1,a2alt,a3alt}}];
   If[normValid && altValid && Not[IsZero2D[s3-s3alt]],
      Message[SolveTriangle2D::ambiguous,
              Not[D2D$SolveTriangle2D$AlternateSolution]]];
   Switch[{normValid,altValid,D2D$SolveTriangle2D$AlternateSolution},
      {True ,True ,True }, s3alt,
      {True ,True ,False}, s3,
      {True ,False,True }, s3,
      {True ,False,False}, s3,
      {False,True, True }, s3alt,
      {False,True, False}, s3alt,
      {False,False,True }, Null,
      {False,False,False}, Null]];

No other cases match, just return the configuration.

SolveTriangle$2D[{S:{s1_,s2_,s3_},A:{a1_,a2_,a3_}}]:={S,A};

Transformations

Reflect

Format: Reflect2D[triangle,line]
Reflects a triangle in a line.

Reflect2D[Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],
          L2:Line2D[A2_,B2_,C2_]] :=
   Triangle2D[Reflect2D[{x1,y1},L2],
              Reflect2D[{x2,y2},L2],
              Reflect2D[{x3,y3},L2]];

Rotate

Format: Rotate2D[triangle,θ,coords]
Rotates a triangle by an angle θ about a position specified by a coordinate list.  If the third argument is omitted, it defaults to the origin (see D2DTransform2D.html).

Rotate2D[Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],theta_?IsScalar2D,
         {h_?IsScalar2D,k_?IsScalar2D}] :=
   Triangle2D[Rotate2D[{x1,y1},theta,{h,k}],
              Rotate2D[{x2,y2},theta,{h,k}],
              Rotate2D[{x3,y3},theta,{h,k}]];

Scale

Format: Scale2D[triangle,s,coords]
Scales a triangle from a position given by coordinates.  If the third argument is omitted, it defaults to the origin (see D2DTransform2D.html).

Scale2D[Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],s_?IsScalar2D,
        {h_?IsScalar2D,k_?IsScalar2D}] :=
   Triangle2D[Scale2D[{x1,y1},s,{h,k}],
              Scale2D[{x2,y2},s,{h,k}],
              Scale2D[{x3,y3},s,{h,k}]] /;
Not[IsZeroOrNegative2D[s]];

Translate

Format: Translate2D[triangle,{u,v}]
Translates a point delta distance.

Translate2D[Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],
            {u_?IsScalar2D,v_?IsScalar2D}] :=
   Triangle2D[{x1+u,y1+v},{x2+u,y2+v},{x3+u,y3+v}];

Point Construction

Centroid

Format: Point2D[triangle,Centroid2D]
Constructs the centroid point of a triangle. The centroid is the intersection of the medians of the triangle (the lines connecting the vertices to the midpoints of the sides).


Point2D[Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],Centroid2D] :=
   Point2D[{x1+x2+x3,y1+y2+y3}/3];

Center of Circumscribed Circle

Format: Point2D[triangle,Circumscribed2D]
Constructs the center of the circle that circumscribes a triangle. The center of the circumscribed circle is the intersection of the perpendicular bisectors of the triangle sides.

Point2D[Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],Circumscribed2D] :=
   Point2D[Circle2D[Point2D[{x1,y1}],Point2D[{x2,y2}],Point2D[{x3,y3}]]];

Center of Inscribed Circle

Format: Point2D[triangle,Inscribed2D]
Constructs the center of the circle that inscribes a triangle. The center of the inscribed circle is the intersection of the angle bisectors of the triangle sides.

Point2D[T1:Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],Inscribed2D] :=
   Point2D[Circle2D[T1,Inscribed2D]];

Vertex Point

Format: Point2D[triangle,n]
Constructs a vertex point of a triangle.  The vertex points are numbered from 1 to 3.

Point2D[T1:Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],n_?IsVertex$2D] :=
   Point2D[T1[[n]]];

Line Construction

Side of a Triangle

Format: Line2D[triangle,"D2DTriangle2D_38.gif","D2DTriangle2D_39.gif"]
Constructs the line associated with vertices "D2DTriangle2D_40.gif" and "D2DTriangle2D_41.gif" of a triangle.

Line2D[T:Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],
       n1_?IsVertex$2D,
       n2_?IsVertex$2D] :=
   Line2D[T[[n1]],T[[n2]]] /;
(n1!=n2);

Line Segment Construction

Side of a Triangle

Format: Segment2D[triangle,"D2DTriangle2D_42.gif","D2DTriangle2D_43.gif"]
Constructs the line segment associated vertices "D2DTriangle2D_44.gif" and "D2DTriangle2D_45.gif" of a triangle.

Segment2D[T:Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],
          n1_?IsVertex$2D,
          n2_?IsVertex$2D] :=
   Segment2D[T[[n1]],T[[n2]]] /;
(n1!=n2);

Circle Construction

Circumscribed Circle

Format: Circle2D[triangle,Circumscribed2D]
Constructs a circle that circumscribes a triangle.

Circle2D[Triangle2D[{x1_,y1_},{x2_,y2_},{x3_,y3_}],Circumscribed2D] :=
   Circle2D[Point2D[{x1,y1}],Point2D[{x2,y2}],Point2D[{x3,y3}]];

Inscribed Circle

Format: Circle2D[triangle,Inscribed2D]
Constructs a circle inscribed in a triangle.

Circle2D[Triangle2D[p1:{x1_,y1_},p2:{x2_,y2_},p3:{x3_,y3_}],Inscribed2D] :=
   Module[{s1,s2,s3,s,r,h,k},
      s1=Distance2D[p2,p3];
      s2=Distance2D[p1,p3];
      s3=Distance2D[p1,p2];
      s=(s1+s2+s3)/2;
      r=Sqrt[(s-s1)*(s-s2)*(s-s3)/s];
      {h,k}=(s1*{x1,y1}+s2*{x2,y2}+s3*{x3,y3})/(2*s);
      Circle2D[{h,k},r] ];

Triangle Construction

Triangle from Three Points

Format: Triangle2D[point,point,point]
Constructs a triangle from three vertex points.

Triangle2D[Point2D[{x1_,y1_}],Point2D[{x2_,y2_}],Point2D[{x3_,y3_}]] :=
   Triangle2D[{x1,y1},{x2,y2},{x3,y3}];

Triangle from Three Lines

Format: Triangle2D[line,line,line]
Constructs a triangle from three lines that define the sides of the triangle.

Triangle2D::noTriangle=
   "Two of the lines `1` are parallel, or the three are concurrent; no triangle exists.";

Triangle2D[L1:Line2D[a1_,b1_,c1_],
           L2:Line2D[a2_,b2_,c2_],
           L3:Line2D[a3_,b3_,c3_]] :=
   If[IsParallel2D[{L1,L2,L3}] || IsConcurrent2D[L1,L2,L3],
      Message[Triangle2D::noTriangle,{L1,L2,L3}];$Failed,
      Triangle2D[Point2D[L1,L2],Point2D[L1,L3],Point2D[L2,L3]] ];

Triangle from Sides/Angles

Format: Triangle2D[{"D2DTriangle2D_46.gif","D2DTriangle2D_47.gif","D2DTriangle2D_48.gif"}]
Constructs a triangle in standard position from a configuration of three side lengths.  The first vertex will be at the origin and the second on the +x-axis.

Triangle2D[{s1_?IsScalar2D,s2_?IsScalar2D,s3_?IsScalar2D}]:=
   Triangle2D[{{s1,s2,s3},{Null,Null,Null}}];

Format: Triangle2D[{{"D2DTriangle2D_49.gif","D2DTriangle2D_50.gif","D2DTriangle2D_51.gif"},{"D2DTriangle2D_52.gif","D2DTriangle2D_53.gif","D2DTriangle2D_54.gif"}},(True | False)]
Constructs a triangle in standard position from a configuration of side lengths and angles.  The first vertex will be at the origin and the second on the +x-axis.  Three of the six configuration parameters are expected, and the others should be set to Null.  If more than three configuration parameters are specified, then they must be consistent.  The second argument, when set to True, returns an alternate solution if two solutions exist; if omitted, it defaults to False.

Triangle2D[{
   S:{s1_?IsScalar2D | Null,s2_?IsScalar2D | Null,s3_?IsScalar2D | Null},
   A:{a1_?IsScalar2D | Null,a2_?IsScalar2D | Null,a3_?IsScalar2D | Null}},
   alternateSolution_:False]:=
Module[{SA,S1,S2,S3,A1,A2,A3,f1,f2,a,b,d},
   SA=SolveTriangle2D[{S,A},alternateSolution];
   If[SA===$Failed,$Failed,
      {{S1,S2,S3},{A1,A2,A3}}=SA;
      f1=-S1^2+S2^2+S3^2;
      f2=-(S1-S2-S3)(S1+S2-S3)(S1-S2+S3)(S1+S2+S3);
      Triangle2D[{0,0},{d,0},{a,b}] /.
         {a->f1/(2*S3),b->Sqrt[f2/S3^2]/2,d->S3}] ] /;
MemberQ[{True,False},alternateSolution];

Epilogue

End[ ]; (* end of "`Private" *)
EndPackage[ ]; (* end of "D2DTriangle2D`" *)


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