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[{
,
},{
,
},{
,
}]
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[{
,
},{
,
},{
,
}]
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[{
,
},{
,
},{
,
}]
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[{{
,
,
},{
,
,
}}] 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[{{
,
,
},{
,
,
}}] 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[{{
,
,
},{
,
,
}},(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
.
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,
,
]
Constructs the line associated with vertices
and
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,
,
]
Constructs the line segment associated vertices
and
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[{
,
,
}]
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[{{
,
,
},{
,
,
}},(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`" *)