/mj/HalfOctant4.pl
Perl | 1202 lines | 858 code | 91 blank | 253 comment | 179 complexity | 2d06a06c705e6d799fdf81a217d8321a MD5 | raw file
- #! /usr/bin/perl -w
- # Program HalfOctant4. (made from HalfOctant3.odt on 2010-04-03)
- #
- # In this version, all parallels are equidistant from equator to pole, along meridians.
- # There are no polar circular arcs. In other HalfOctant#.odt versions, dP was a hash, %dP,
- # with parallel spacings for polar, supple, temperate and torrid zones. In this version, it is
- # only an array, @dP, with a single parallel spacing value for each meridian.
-
- use Math::Trig;
-
- # Some constants for use by Subroutine MJtoG, which does coordinate axis transformation.
- # Angle of rotation is 60°. Point G is (10000,0) in MJ, and (5000,0) in G
- $cos60 = cos (deg2rad(60));
- $sin60 = sin (deg2rad(60));
- $yTranslate = 10000 * $sin60;
-
- # Multidimensional arrays are done with hashes, with the keys used for i,j indeces.
-
- # Given input
- $xM = 0; $yM = 0; # Point M is the origin of the axes
- $MA = 940; # Indent of octant's apex, with respect to triangle's
- $xG = 10000; $yG = 0; # Point G, at center of base of octant
- $DeltaFrigid = 104; # Distance for each degree of latitude close to the pole
-
- # Other points and lengths of special interest
- $xA = $MA; $yA = 0; # Point A, at the indent
- $xN = $xG; $yN = $xG * tan (deg2rad(30)); # Point N
- ($flag, $xB, $yB) = LineIntersection ($xM,$yM,30,$xA,$yA,45); # Point B
- if ($flag ne "Intersect") { die "$flag while calculating point B.\n"; }
- $AG = $xG - $xA;
- $AB = Length ($xA, $yA, $xB, $yB);
- $EF = $AB; # Sometimes I prefer AB, others EF
- $MB = Length ($xM, $yM, $xB, $yB);
- $MN = Length ($xM, $yM, $xN, $yN);
- $xD = Interpolate ($MB, $MN, $xN, $yM); # D is away from N as B is away from M
- $yD = Interpolate ($MB, $MN, $yN, $yM);
- $xF = $xG;
- $yF = $yN - $MB;
- $xE = $xN - $MA * sin (deg2rad(30));
- $yE = $yN - $MA * cos (deg2rad(30));
- $FG = $yF;
- $BD = Length ($xB, $yB, $xD, $yD);
- $EFG = $EF + $FG;
-
- # Calculate polar start, two joints, and equatorial end, for each meridian; hashes %xJ, %yJ.
- # Also calculate a few other values for other hashes, on the way.
-
- $DeltaMEq = $EFG / 45; # 45 meridian spacings along equator for half an octant
-
- foreach $m (0 .. 45) { # Loop for each meridian.
- $M = $m . ',' ; # part of hash key (array row number)
-
- # Start point of minor meridians will be modified to be at parallel 85° after that
- # parallel has been calculated. For now, all meridians are set to start at point A.
- $xJ {$M . 0} = $xA; $yJ {$M . 0} = $yA;
-
- # End point of meridians, that is, equidistant intersections with equator;
- # These are also the meridian crossings for the zero-th parallel
- $distance = $m * $DeltaMEq;
- if ($distance <= $yF) {
- $xJ {$M . 3} = $xP {$M . 0} = $xG;
- $yJ {$M . 3} = $yP {$M . 0} = $distance;
- } else { # Past joint at point F
- $extra = $distance - $yF;
- $xJ {$M . 3} = $xP {$M . 0} = Interpolate ($extra, $EF, $xF, $xE);
- $yJ {$M . 3} = $yP {$M . 0} = Interpolate ($extra, $EF, $yF, $yE);
- }
-
- # Calculate both joints of meridians
-
- if ($m == 0) { # Straight, centre of octant meridian
- # This is a good place to calculate a bunch of things for centre line, AG.
-
- # No joints; give coordinates of point G for the joints
- @xJ {$M . 1, $M . 2} = ($xG, $xG);
- @yJ {$M . 1, $M . 2} = ($yG, $yG);
- # Lenght of meridian segments; this whole meridian is a single segment
- @L {$M . 0, $M . 1, $M . 2, $M . 3, $M . 4} = ($AG, 0, 0, $AG, $AG);
- # May as well calculate parallel intersections along this straight line
- $dP [$m] = $L{$M . 4} / 90;
- foreach $p (1 .. 89) {
- $xP {$M . $p} = $xG - $p * $dP[$m];
- $yP {$M . $p} = $yG;
- }
- } else { # Meridians other than 0°.
- # Calculate joints by line intersection from A and M
- ($flag, $xJ {$M . 1}, $yJ {$M . 1}) =
- LineIntersection ($xM, $yM, 2*$m/3, $xA, $yA, $m);
- if ($flag ne "Intersect") { die "$flag while calculating 1st joint at $m.\n"; }
- ($flag, $xJ {$M . 2}, $yJ {$M . 2}) =
- LineIntersection ($xM, $yM, 2*$m/3, $xJ {$M . 3}, $yJ {$M . 3}, $m/3);
- if ($flag ne "Intersect") { die "$flag while calculating 2nd joint at $m.\n"; }
- # Calculate length of meridian segments: These are calculated from point A
- # to equator, even if this meridian starts at parallel 85°.
- $L {$M . 0} = Length ($xA, $yA, $xJ {$M . 1}, $yJ {$M . 1});
- $L {$M . 1} = Length ($xJ {$M . 1}, $yJ {$M . 1}, $xJ {$M . 2}, $yJ {$M . 2});
- $L {$M . 2} = Length ($xJ {$M . 2}, $yJ {$M . 2}, $xJ {$M . 3}, $yJ {$M . 3});
- $L {$M . 3} = $L {$M . 1} + $L {$M . 2}; # Torrid + Temperate
- $L {$M . 4} = $L {$M . 3} + $L {$M . 0}; # Total meridian length from A
- # Calculate parallel intersections
- $dP[$m] = $L {$M . 4} / 90; # Distance between parallels
- foreach $p (1 .. 89) {
- $distance = $p * $dP [$m];
- if ($distance <= $L {$M . 2} ) { # Torrid segment
- $xP{$M.$p} =
- Interpolate ($distance, $L{$M.2}, $xJ{$M.3}, $xJ{$M.2});
- $yP{$M.$p} =
- Interpolate ($distance, $L{$M.2}, $yJ{$M.3}, $yJ{$M.2});
- } elsif ($distance <= $L {$M . 3} ) { # Temperate seg., past one joint
- $extra = $distance - $L {$M . 2};
- $xP{$M.$p} =
- Interpolate ($extra, $L{$M.1}, $xJ{$M.2}, $xJ{$M.1});
- $yP{$M.$p} =
- Interpolate ($extra, $L{$M.1}, $yJ{$M.2}, $yJ{$M.1});
- } else { # Frigid segment, past two joints
- $extra = $distance - $L {$M . 3};
- $xP{$M.$p} = Interpolate ($extra, $L{$M.0}, $xJ{$M.1}, $xA);
- $yP{$M.$p} = Interpolate ($extra, $L{$M.0}, $yJ{$M.1}, $yA);
- }
- } # End of foreach $p loop, that is, end of parallel calculation
- } # End of calculating meridian joints
- } # End of loop for each meridian.
-
- # Start point of every meridian was previously set to be point A. However, the drawn
- # line for the minor meridians will start at parallel 85°; this could not be set previously
- # because that parallel still hadn't been calculated.
- foreach $m (0 .. 45) {
- $M = $m . ',' ;
- unless ($m % 5 == 0) {
- $xJ {$M . 0} = $xP {$M . 85};
- $yJ {$M . 0} = $yP {$M . 85};
- }
- }
-
- # Output all the values.
- $PointFormat = "%3s \t%11.4f \t%11.4f\n";
- $LengthFormat = "%s \t%11.4f\n";
- $HashKeyValue = "%4s \t%11.4f\n";
-
- $Skip = "Yes";
- unless ($Skip) { # Option to skip printing hashes in spreadsheet readable csv format
- open (CSV, ">Macros4\/Hashes4.csv");
- print CSV "\ndP\n"; # @dP is an array, not a hash; can't use sub PrintHash
- foreach $i (0 .. 45) { printf CSV "\t%10d",$i; } print CSV "\n";
- print CSV " ";
- foreach $m (0 .. 45) {
- if (defined ($dP[$m]) ) {printf CSV "\t%11.4f",$dP[$m];
- } else { printf CSV "\t undef"; }
- }
- print CSV "\n";
- print CSV "\nL\n"; PrintHash (4,%L);
- print CSV "\nxJ\n"; PrintHash (3,%xJ);
- print CSV "\nyJ\n"; PrintHash (3,%yJ);
- print CSV "\nxP\n"; PrintHash (89,%xP);
- print CSV "\nyP\n"; PrintHash (89,%yP);
- close (CSV);
- print 'Wrote values of arrays to file "Macros4/Hashes4.csv".', "\n";
- } # End of Skip printing hashes in Spreadsheet readable csv format
-
- $Skip = "Yes";
- unless ($Skip) { # Option to skip printing, hashes by their keys
- print "\n* * * Keys of hashes\n\n";
- print "* * * \%xJ\n";
- foreach $key (keys (%xJ)) {
- printf ($HashKeyValue, $key, $xJ{$key});
- }
- print "* * * \%yJ\n";
- foreach $key (keys (%yJ)) {
- printf ($HashKeyValue, $key, $yJ{$key});
- }
- print "* * * \%L\n";
- foreach $key (keys (%L)) {
- printf ($HashKeyValue, $key, $L{$key});
- }
- print "\n* * * COORDINATES\n";
- print "* * * \%xP\n";
- foreach $key (keys (%xP)) {
- printf ($HashKeyValue, $key, $xP{$key});
- }
- print "* * * \%yP\n";
- foreach $key (keys (%yP)) {
- printf ($HashKeyValue, $key, $yP{$key});
- }
- } # End of Skip of printing hashes by their keys
-
- $Skip = "Yes";
- unless ($Skip) { # Option to skip printing points and lengths
- print "* * * Major points (point, x, y);\n";
- printf ($PointFormat, "M", $xM, $yM);
- printf ($PointFormat, "N", $xN, $yN);
- printf ($PointFormat, "A", $xA, $yA);
- printf ($PointFormat, "B", $xB, $yB);
- printf ($PointFormat, "D", $xD, $yD);
- printf ($PointFormat, "E", $xE, $yE);
- printf ($PointFormat, "F", $xF, $yF);
- printf ($PointFormat, "G", $xG, $yG);
- # Main lengths
- print "\n* * * Main lengths\n";
- printf ($LengthFormat,'MG',$xG);
- printf ($LengthFormat,'MN',$MN);
- printf ($LengthFormat,'MA',$MA);
- printf ($LengthFormat,'MB',$MB);
- printf ($LengthFormat,'AG',$AG);
- printf ($LengthFormat,'AB',$AB);
- printf ($LengthFormat,'BD',$BD);
- printf ($LengthFormat,'EF',$EF);
- printf ($LengthFormat,'FG',$FG);
- printf ($LengthFormat,'EFG',$EFG);
- printf ($LengthFormat,'ABDE',2 * $EFG);
- print "\n";
- printf ($LengthFormat,'Frigid parallel spacing',$DeltaFrigid);
- printf ($LengthFormat,'Equatorial meridian spacing',$DeltaMEq);
- } # End of Skip of printing major points and lengths
-
- # Make TurboCAD macros.
- # Scaffold triangle macro
-
- $Skip = "Yes";
- unless ($Skip) { # Option to skip making macro files of half octant or one octant
- StartMacroFile (MACRO, "Macros4\/Triangle.txt");
- print MACRO ("Pen 9\r");
- print MACRO ("Line ", Coordinate($xM, $yM), Coordinate ($xN, $yN), "\\\r");
- print MACRO (Coordinate($xG, $yG), Coordinate ($xM, $yM), '[`;`]', "\r");
- EndMacroFile (MACRO);
- print 'Wrote file "Macros4/Triangle.txt".', "\n";
-
- # And the same thing in Gene's coordinate system
- StartMacroFile (MACRO, "Macros4\/TriangleG.txt");
- print MACRO ("Pen 9\r");
- print MACRO ("Line ", Coordinate(MJtoG($xM,$yM)), Coordinate(MJtoG($xN,$yN)), "\\\r");
- print MACRO (Coordinate(MJtoG($xG,$yG)), Coordinate(MJtoG($xM,$yM)), '[`;`]', "\r");
- EndMacroFile (MACRO);
- print 'Wrote file "Macros4/TriangleG.txt."', "\n";
-
- # Half-octant outline macro
- StartMacroFile (MACRO, "Macros4\/Half-Octant.txt");
- print MACRO ("Pen 12\r");
- print MACRO ("Line ", Coordinate($xA, $yA), Coordinate ($xB, $yB), "\\\r");
- print MACRO (Coordinate($xD, $yD), Coordinate ($xE, $yE), "\\\r");
- print MACRO (Coordinate($xF, $yF), Coordinate ($xG, $yG), '[`;`]', "\r");
- EndMacroFile (MACRO);
- print 'Wrote file "Macros4/Half-Octant.txt".', "\n";
-
- # And the same thing in Gene's coordinate system
- StartMacroFile (MACRO, "Macros4\/Half-OctantG.txt");
- print MACRO ("Pen 12\r");
- print MACRO ("Line ", Coordinate(MJtoG($xA,$yA)), Coordinate(MJtoG($xB, $yB)), "\\\r");
- print MACRO (Coordinate(MJtoG($xD,$yD)), Coordinate(MJtoG($xE, $yE)), "\\\r");
- print MACRO (Coordinate(MJtoG($xF,$yF)), Coordinate(MJtoG($xG, $yG)), '[`;`]', "\r");
- EndMacroFile (MACRO);
- print 'Wrote file "Macros4/Half-OctantG.txt".', "\n";
-
- # Macro of 8 equilateral triangles
- StartMacroFile (MACRO, "Macros4\/MScaffold.txt");
- print MACRO ("Pen 9\r");
- MLinesMacro (MACRO,0,$xN,-$yN,1,$xM,$yM,1,$xN,$yN,1,$xN,-$yN,1,$xM,$yM,6,
- $xN,$yN,1,$xN,$yN,2,$xM,$yM,1);
- MLinesMacro (MACRO,0,$xN,$yN,1,$xM,$yM,7,$xN,$yN,2,$xN,$yN,3,$xM,$yM,7);
- MLinesMacro (MACRO,0,$xN,$yN,2,$xM,$yM,3,$xN,$yN,3,$xN,$yN,4,$xM,$yM,3);
- MLinesMacro (MACRO,0,$xN,$yN,3,$xM,$yM,5,$xN,$yN,4);
- EndMacroFile (MACRO);
- print 'Wrote file "Macros4/MScaffold.txt".', "\n";
-
- # Macro of 8 Octants
- StartMacroFile (MACRO, "Macros4\/MOctants.txt");
- print MACRO ("Pen 12\r");
- MLinesMacro (MACRO,6, $xF,$yF,$xF,-$yF,$xE,-$yE,$xD,-$yD,$xB,-$yB,
- $xA,$yA,$xB,$yB,$xD,$yD,$xE,$yE,$xF,$yF);
- MLinesMacro (MACRO,1, $xF,-$yF,$xE,-$yE,$xD,-$yD,$xB,-$yB,
- $xA,$yA,$xB,$yB,$xD,$yD,$xE,$yE,$xF,$yF);
- MLinesMacro (MACRO,2, $xB,-$yB,$xA,$yA,$xB,$yB,$xD,$yD,$xE,$yE,
- $xF,$yF,$xF,-$yF,$xE,-$yE,$xD,-$yD);
- MLinesMacro (MACRO,7, $xF,-$yF,$xE,-$yE,$xD,-$yD,$xB,-$yB,
- $xA,$yA,$xB,$yB,$xD,$yD,$xE,$yE,$xF,$yF);
- MLinesMacro (MACRO,8, $xB,-$yB,$xA,$yA,$xB,$yB,$xD,$yD,$xE,$yE,
- $xF,$yF,$xF,-$yF,$xE,-$yE,$xD,-$yD);
- MLinesMacro (MACRO,3, $xF,-$yF,$xE,-$yE,$xD,-$yD,$xB,-$yB,
- $xA,$yA,$xB,$yB,$xD,$yD,$xE,$yE,$xF,$yF);
- MLinesMacro (MACRO,5, $xF,-$yF,$xE,-$yE,$xD,-$yD,$xB,-$yB,
- $xA,$yA,$xB,$yB,$xD,$yD,$xE,$yE,$xF,$yF);
- MLinesMacro (MACRO,4, $xB,-$yB,$xA,$yA,$xB,$yB,$xD,$yD,$xE,$yE,
- $xF,$yF,$xF,-$yF,$xE,-$yE,$xD,-$yD);
- EndMacroFile (MACRO);
- print 'Wrote file "Macros4/MOctants.txt".', "\n";
-
- # Meridians macros
-
- StartMacroFile (MAJOR, "Macros4\/MajorMeridians.txt");
- print MAJOR ("Pen 12\r");
- StartMacroFile (MINOR, "Macros4\/MinorMeridians.txt");
- print MINOR ("Pen 13\r");
- MeridianMacro ();
- EndMacroFile (MAJOR);
- EndMacroFile (MINOR);
- print 'Wrote files "Macros4/MajorMeridians.txt" and "Macros4/MinorMeridians.txt".', "\n";
-
- # Parallels macros
- StartMacroFile (MAJOR, "Macros4\/ParallelsMajor.txt");
- print MAJOR ("Pen 12\r");
- StartMacroFile (MINOR, "Macros4\/ParallelsMinor.txt");
- print MINOR ("Pen 13\r");
- ParallelMacro (1,89,0,45);
- EndMacroFile (MAJOR);
- EndMacroFile (MINOR);
- print 'Wrote files "Macros4/ParallelsMajor.txt" and "Macros4/ParallelsMinor.txt".', "\n";
- } # End of Skip of making macro files of half octant or one octant
-
- $Skip = "Yes";
- unless ($Skip) { # Option to skip making macro files of parallel points and of joints points
- # Macro of points for the intersections of the parallels with the meridians; this will be
- # a large file which will take quite awhile to plot; pens to be used are specified in the
- # subroutine. Meant only to check if the data seems right.
- StartMacroFile (MACRO, "Macros4\/Points.txt");
- PointsMacro ();
- EndMacroFile (MACRO);
- print 'Wrote file "Macros4/Points.txt".', "\n";
-
- # Macro of meridian joints and end points (4 points per meridian)
- StartMacroFile (MACRO, "Macros4\/Joints.txt");
- JointsMacro ();
- EndMacroFile (MACRO);
- print 'Wrote file "Macros4/Joints.txt".', "\n";
- } # End of Skip of making macro files
-
- # Macros for all eight whole octants
-
- $Skip = "Yes";
- unless ($Skip) { # Option to skip making macro files of eight octants
- # Make arrays for Octant; I should have done this much earlier in the program
- @xOct = ($xA,$xB,$xD,$xE,$xF,$xG);
- @yOct = ($yA,$yB,$yD,$yE,$yF,$yG);
-
- # Make a copy of arrays and hashes that I will want to convert; the other ones
- # will be changed to coordinates for different octant halves.
- @xOctC = @xOct; @yOctC = @yOct;
- %xJC = %xJ; %yJC = %yJ;
- %xPC = %xP; %yPC = %yP;
-
- # Make grid files
- StartMacroFile (MINOR, "Macros4\/M-Grid-Minor.txt");
- print MINOR ("Pen 15\r");
- GridMacro (MINOR, -20000,20000,-10000,10000,100,1000);
- EndMacroFile (MINOR);
-
- StartMacroFile (MAJOR, "Macros4\/M-Grid-Major.txt");
- print MAJOR ("Pen 14\r");
- GridMacro (MAJOR, -20000,20000,-10000,10000,1000,0);
- EndMacroFile (MAJOR);
-
- StartMacroFile (MAJOR, "Macros4\/M-Grid-5Kred.txt");
- print MAJOR ("Pen 10\r");
- GridMacro (MAJOR, -20000,20000,-10000,10000,5000,0);
- EndMacroFile (MAJOR);
-
- print 'Wrote files "M-Grid-Minor.txt", "M-Grid-Major.txt" and "M-Grid-5Kred.txt" in "Macros4/".',
- "\n";
- # Draw octants, half at a time
- StartMacroFile (MACRO, "Macros4\/M-Octants.txt");
- print MACRO ("Pen 11\r");
- foreach $Oct (1 .. 8) { # For octant 1 and octant 2
- foreach $i (0..5) { # For each point (A,B,D,E,F,G)
- ($xOct[$i],$yOct[$i]) = MJtoG ($xOctC[$i],-$yOctC[$i],$Oct); # West half
- }
- OctantMacro ();
- foreach $i (0..5) {
- ($xOct[$i],$yOct[$i]) = MJtoG ($xOctC[$i],$yOctC[$i],$Oct); # East half
- }
- OctantMacro ();
- }
- EndMacroFile (MACRO);
- print 'Wrote file "Macros4/M-Octants.txt".', "\n";
-
- # Draw Meridians, half an octant at a time
- StartMacroFile (MINOR, "Macros4\/M-Meridians-Minor.txt");
- StartMacroFile (MAJOR, "Macros4\/M-Meridians-Major.txt");
- print MINOR ("Pen 13\r");
- print MAJOR ("Pen 12\r");
-
- foreach $Oct (1 .. 8) { # For each octant
- # West half of octant
- foreach $m (0..45) {
- $M = $m . ',' ;
- foreach $i (0..3) {
- ($xJ{$M.$i},$yJ{$M.$i}) = MJtoG ($xJC{$M.$i},-$yJC{$M.$i},$Oct);
- }
- }
- MeridianMacro ();
-
- # East half of octant
- foreach $m (0..45) {
- $M = $m . ',' ;
- foreach $i (0..3) {
- ($xJ{$M.$i},$yJ{$M.$i}) = MJtoG ($xJC{$M.$i},$yJC{$M.$i},$Oct);
- }
- }
- MeridianMacro ();
- }
- EndMacroFile (MINOR);
- EndMacroFile (MAJOR);
- print 'Wrote files "Macros4/M-Meridians-Minor.txt" and "Macros4/M-Meridians-Major.txt".', "\n";
-
- # Draw Parallels, half an octant at a time
- StartMacroFile (MINOR, "Macros4\/M-Parallels-Minor.txt");
- StartMacroFile (MAJOR, "Macros4\/M-Parallels-Major.txt");
- print MINOR ("Pen 13\r");
- print MAJOR ("Pen 12\r");
-
- foreach $Oct (1 .. 8) { # For each octant
- # West half of octant
- foreach $m (0..45) { # Convert coordinates
- $M = $m . ',' ;
- foreach $p (0..89) {
- ($xP{$M.$p},$yP{$M.$p}) = MJtoG ($xPC{$M.$p},-$yPC{$M.$p},$Oct);
- }
- }
- # All parallels from 1° to 89° of latitude; skip parallel 0° – octant boundary
- ParallelMacro (1, 89, 0, 45, ", Octant $Oct West");
-
- # East half of octant
- foreach $m (0..45) { # Convert coordinates
- $M = $m . ',' ;
- foreach $p (0..89) {
- ($xP{$M.$p},$yP{$M.$p}) = MJtoG ($xPC{$M.$p},$yPC{$M.$p},$Oct);
- }
- }
- # All parallels from 1° to 89° of latitude; skip parallel 0° – octant boundary
- ParallelMacro (1, 89, 0, 45, ", Octant $Oct East");
- }
- EndMacroFile (MINOR);
- EndMacroFile (MAJOR);
- print 'Wrote file "Macros4/M-Parallels-Minor.txt" and "Macros4/M-Parallels-Major.txt".', "\n";
-
- # Draw Parallels, half an octant at a time, but connecting only nodes of major meridians;
- # that is, not connecting nodes of minor meridians
- StartMacroFile (MINOR, "Macros4\/M-Parallels-Minor5.txt");
- StartMacroFile (MAJOR, "Macros4\/M-Parallels-Major5.txt");
- print MINOR ("Pen 13\r");
- print MAJOR ("Pen 12\r");
-
- foreach $Oct (1 .. 8) { # For each octant
- # West half of octant
- foreach $m (0..45) { # Convert coordinates
- $M = $m . ',' ;
- foreach $p (0..89) {
- ($xP{$M.$p},$yP{$M.$p}) = MJtoG ($xPC{$M.$p},-$yPC{$M.$p},$Oct);
- }
- }
- # All parallels from 1° to 89° of latitude; skip parallel 0° – octant boundary
- ParallelMacro5 (1, 89, 0, 45, ", Octant $Oct West");
-
- # East half of octant
- foreach $m (0..45) { # Convert coordinates
- $M = $m . ',' ;
- foreach $p (0..89) {
- ($xP{$M.$p},$yP{$M.$p}) = MJtoG ($xPC{$M.$p},$yPC{$M.$p},$Oct);
- }
- }
- # All parallels from 1° to 89° of latitude; skip parallel 0° – octant boundary
- ParallelMacro5 (1, 89, 0, 45, ", Octant $Oct East");
- }
- EndMacroFile (MINOR);
- EndMacroFile (MAJOR);
- print 'Wrote file "Macros4/M-Parallels-Major5.txt" and "Macros4/M-Parallels-Minor5.txt".', "\n";
-
- } # End of skip of making macro files of eight octants
-
- # Read some Coastal Data, convert to M-map coordinates, and output a TurboCAD macro.
- # File read is of MAPGEN data format: two columns ASCII flat file with: longitude tab latitude;
- # at the start of each segment there is a line containing only "# -b".
- # This particular file covers longitude from -67° to -59° and latitude from 43° to 48°, that is,
- # Nova Scotia's area. File is 5781.dat.gz, is zipped, and has 92,227 lines.
-
- $Skip = "Yes";
- unless ($Skip) { # Option to skip making macro files of Coastal Data
- print "Going to read land data.\n";
- $maxX=-99999; $maxY=-99999; $minX=999999; $minY=999999;
- StartMacroFile (LAND, "Macros4\/NSmacro.txt");
- print LAND ("Pen 0\r");
- open (DATA, "zcat 5781.dat.gz | ");
- $nData = 0;
- while (<DATA>) {
- $Line = $_ ;
- chomp($Line);
- $nData ++;
- if ($nData % 1000 == 0) { print "Read $nData lines of land data so far.\n"; }
- if ($Line ne "\# -b") {
- ($Long,$Lat) = split(/\t/,$Line);
- # Convert to M-map x and y coordinates
- ($x,$y) = Real2Map ($Long,$Lat);
- # Keep track of maximum and minimum values
- if ($x < $minX) {$minX = $x;}
- if ($x > $maxX) {$maxX = $x;}
- if ($y < $minY) {$minY = $y;}
- if ($y > $maxY) {$maxY = $y}
- # Make arrays of points for this segment to be used by LandMacro
- push (@Xs,$x);
- push (@Ys,$y);
- } elsif (defined(@Xs) ) { # Do only if data points have already been read
- LandMacro (); # Draw the segment of boundary with arrays @Xs and @Ys
- @Xs = (); @Ys = (); # Empty arrays, ready for next segment
- }
- }
- close (DATA);
- if ($Line ne "\# -b") { # Draw last segment, if it hasn't been drawn
- LandMacro ();
- }
- EndMacroFile (LAND);
- print "Read a total of $nData lines, and wrote file",' "Macros4/NSmacro.txt".', "\n";
- print $minX, ' <= x <= ',$maxX," and ",$minY, ' <= y <= ', $maxY, "\n";
-
- } # End of skipping making macro for Coastal Data
-
- $Skip = "";
- unless ($Skip) { # Option to skip making macro file of NS 1:2M of Coastal Data
- print "Going to read land data.\n";
- $maxX=-99999; $maxY=-99999; $minX=999999; $minY=999999;
- StartMacroFile (LAND, "Macros4\/NS-2M-macro4.txt");
- print LAND ("Pen 0\r");
- open (DATA, "zcat NS-2M.dat.gz | ");
- $nData = 0;
- while (<DATA>) {
- $Line = $_ ;
- chomp($Line);
- $nData ++;
- if ($nData % 1000 == 0) { print "Read $nData lines of land data so far.\n"; }
- if ($Line ne "\# -b") {
- ($Long,$Lat) = split(/\t/,$Line);
- # Convert to M-map x and y coordinates
- ($x,$y) = Real2Map ($Long,$Lat);
- # Keep track of maximum and minimum values
- if ($x < $minX) {$minX = $x;}
- if ($x > $maxX) {$maxX = $x;}
- if ($y < $minY) {$minY = $y;}
- if ($y > $maxY) {$maxY = $y}
- # Make arrays of points for this segment to be used by LandMacro
- push (@Xs,$x);
- push (@Ys,$y);
- } elsif (defined(@Xs) ) { # Do only if data points have already been read
- # Shift coordinates to see if TurboCAD plots them better
- $dx = -7600;
- $dy = 3700;
- $n = @Xs -1;
- foreach $i (0..$n) {
- $Xs[$i] = $Xs[$i] - $dx;
- $Ys[$i] = $Ys[$i] - $dy;
- }
- LandMacro (); # Draw the segment of boundary with arrays @Xs and @Ys
- @Xs = (); @Ys = (); # Empty arrays, ready for next segment
- }
- }
- close (DATA);
- if ($Line ne "\# -b") { # Draw last segment, if it hasn't been drawn
- LandMacro ();
- }
- EndMacroFile (LAND);
- print "Read a total of $nData lines, and wrote file",' "Macros4/NS-2M4-macro .txt".', "\n";
- print $minX, ' <= x <= ',$maxX," and ",$minY, ' <= y <= ', $maxY, "\n";
- print "Need plot area ", $maxX-$dx, " by ", $maxY-$dy,".\n";
-
- } # End of skipping making macro for NS, 2:M Coastal Data
-
-
- # - - - - - - - - - SUBROUTINES - - - - - - - - - - - - -
- sub PrintHash {
- # Prints one of my two-dimension arrays in the form of a hash; it is assumed that
- # the indices are separated by a comma, the first indece varies from 0 to 45 and the
- # second indice varies from 0 to the first input parameter.
- # Values are printed to filehandle CSV.
- my ($nI, %Hash) = @_;
- my ($i,$m);
- foreach $i (0 .. 45) { printf CSV "\t%10d",$i; } print CSV "\n";
- foreach $i (0 .. $nI) {
- print CSV $i;
- foreach $m (0 .. 45) {
- if (defined ($Hash{$m.",".$i})) {printf CSV "\t%11.4f",$Hash{$m.",".$i};
- } else { printf CSV "\t undef"; }
- }
- print CSV "\n";
- }
- } # End of subroutine Hash
-
- sub LineIntersection { # Written 2010-02-28
- # Subroutine/function to calculate coordinates of point of intersection of two lines which
- # are given by a point on the line and the line's slope angle in degrees.
- #
- # Return is an array of either one or three values:
- # - if the lines don't intersect or are the same, the return is "Parallel";
- # - if the lines intersect, the returns are: "Intersect" to mean that it worked, and
- # the x and y coordinates of the point of intersection.
- # - if not enough arguments were given or the angles were too large, then return is
- # "Error".
- #
- # Arguments should be 6, in this order:
- # x and y coordinates of point of first line; slope of first line in degrees;
- # x and y coordinates of point of second line; slope of second line in degrees;
- #
- # Equations used are from: slope of line = tangent angle = delta-y / delta-x, and the fact
- # that intersection point x,y is on both lines.
-
- use Math::Trig;
- my ($nArguments,$xp,$yp,$m1,$m2);
- $nArguments=@_ ;
- my ($x1,$y1,$angle1,$x2,$y2,$angle2) = @_ ;
-
- if ($nArguments != 6) { # Not the exact number of arguments
- print "Sub LineIntersection requires 6 arguments but received $nArguments \n";
- return "Error";
- } elsif ($angle1<-180 || $angle2<-180 || $angle1>180 || $angle2>180) { # Angles too large
- print "Sub LineIntersection: Angles should be between -180 and 180. \n";
- return "Error";
- } elsif ($angle1==$angle2 || $angle1 == ($angle2+180) || $angle1 == ($angle2-180) ) {
- return "Parallel"; # Lines are either parallel or the same line
- } elsif ( not defined($x1) || not defined($y1) || not defined($angle1) ||
- not defined($x2) || not defined($y2) || not defined($angle2) ) {
- print ("Undefined in LineInterpolation: $x1,$y1,$angle1,$x2,$y2,$angle2\n");
- return "Error";
- } else { # Lines intersect. Calculate point of intersection.
- if ($angle1 == 0 || $angle1 == 180 || $angle1 == -180) { # Line 1 horizontal
- if ($angle2 == 90 || $angle2 == -90) { # Line 1 horizontal, line 2 vertical
- return ("Intersect",$y1,$x2);
- } else { # Line 1 horizontal, line 2 slanted
- $xp = $x2 - ($y2 - $y1) / tan(deg2rad($angle2));
- return ("Intersect",$xp,$y1);
- }
- } elsif ($angle1 == 90 || $angle1 == -90) { # Calculate when line 1 is vertical
- if ($angle2 == 0 || $angle2 == 180 || $angle2 == -180) {
- # Line 1 vertical, line 2 horizontal
- return ("Intersect",$x1,$y2);
- } else { # Line 1 vertical, line 2 slanted
- $yp = $y2 - ($x2 - $x1) * tan(deg2rad($angle2));
- return ("Intersect",$x1,$yp);
- }
- } elsif ($angle2 == 0 || $angle2 == 180 || $angle2 == -180) {
- # Line 1 slanted, line 2 horizontal
- $xp = $x1 - ($y1 - $y2) / tan(deg2rad($angle1));
- return ("Intersect",$xp,$y2);
- } elsif ($angle2 == 90 or $angle2 == -90) { # Line 1 slanted, line 2 vertical
- $yp = $y1 - ($x1-$x2) * tan(deg2rad($angle1));
- return ("Intersect",$x2,$yp);
- } else { # Line 1 slanted, line 2 slanted
- $m1 = tan(deg2rad($angle1));
- $m2 = tan(deg2rad($angle2));
- $xp = ($m1 * $x1 - $m2 * $x2 - $y1 + $y2) / ($m1 - $m2);
- $yp = $m1 * $xp - $m1 * $x1 + $y1;
- return ("Intersect",$xp,$yp);
- } #End of all the vertical, horizontal, slanted combinations
- } # End of if-else – lines intersect
- } # End of Subroutine LineIntersection
-
- sub Length {
- # Input are x1,y1,x2,y2
- my ($x1,$y1,$x2,$y2) = @_;
- return sqrt( ($x1-$x2)**2 + ($y1-$y2)**2);
- }
-
- sub Interpolate {
- # Inputs are 4: length wanted, of total-segment-length, start, end;
- # Total-segment-length is different from (end - start); end and start may be x-coordinates,
- # or y-coordinates, while length takes into account the other coordinates.
- # (Start - End ) / Length = (Wanted - Start) / NewLength
- # Returns single value: Wanted.
- my ($NewLength, $Length, $Start, $End) = @_;
- my ($Wanted);
- $Wanted = $Start + ($End - $Start) * $NewLength / $Length;
- $Skip = "Yes";
- unless ($Skip) { # Skip of not the printing of arguments and value being returned
- my ($nIn, $i);
- $nIn = @_ - 1;
- # print "Interpolate inputs are ", $nIn+1, ": ";
- foreach $i (0 .. $nIn) {
- if (defined ($_[$i]) ) {
- printf ("%11.4f, ", $_[$i]);
- } else {
- printf ("%11s, ", 'UNDEFINED!');
- }
- }
- if (defined ($Wanted) ) {
- # print "Returning: ";
- printf ("\>%11.4f",$Wanted);
- } else {
- printf ("\>%11s", 'UNDEFINED!');
- }
- print "\n";
- } # End of Skip printing arguments and value being returned
- return $Wanted;
- } # End of subroutine Interpolate
-
- # - - - - - - - - - SUBROUTINES relating to TurboCAD - - - - - - - - - - - - -
-
- sub StartMacroFile {
- my ($FileHandle, $ToOpen);
- $FileHandle = $_ [0];
- $ToOpen = '>' . $_[1];
- open ($FileHandle, $ToOpen);
- print $FileHandle ('#PenWas = %WT.P', "\r");
- }
-
- sub EndMacroFile {
- my ($FileHandle);
- $FileHandle = $_ [0];
- print $FileHandle ('Pen #PenWas', "\r");
- print $FileHandle ("Bell\rBell\r");
- close ($FileHandle);
- }
-
- sub Coordinate {
- # returns string with coordinate format for TurboCAD;
- # expects two arguments: x and y.
- return '[a,' . sprintf ("%11.4f,%11.4f",$_[0],$_[1]) . ',0,` `] '
- }
-
- sub PointsMacro {
- # I will be lazy and use global variables instead of trying to pass hashes as
- # parameters.
- # Plotting all parallel intersections, that have already been calculated: arrays
- # %xP, %yP.
- # Subroutine will prepare TurboCad commands to plot each point. This will be written
- # to filehandle MACRO
- my ($m, $p, $i, $s, $c);
- $s = 'PT Period Pen = #';
- print MACRO ("\#MiMi = 13\r\#MjMi = 12\r\#MjMj = 9\r"); # Pen variables
- print MACRO ($s, 'MjMj ', Coordinate($xA, $yA), '[`;`]', "\r" ); # Point at the pole
- foreach $m (0 .. 45) {
- foreach $p (0 .. 89) {
- $i = $m . "," . $p ;
- if (defined ($xP {$i}) && defined ($yP {$i})) {
- if ($m % 5 == 0 && $p % 5 == 0) {
- $c = 'MjMj'; # major meridian and major parallel
- } elsif ($m % 5 == 0 || $p % 5 == 0) {
- $c = 'MjMi'; # major parallel or major meridian
- } else {
- $c = 'MiMi'; # minor parallel with minor meridian
- }
- print MACRO ($s,$c,' ', Coordinate($xP{$i},$yP{$i}), '[`;`]', "\r" );
- }
- }
- }
- } # End of subroutine PointsMacro.
-
- sub JointsMacro {
- # I will be lazy and use global variables instead of trying to pass hashes as
- # parameters.
- # Plotting all joint intersections, that have already been calculated: arrays
- # %xJ, %yJ.
- # Subroutine will prepare TurboCad commands to plot each point. This will be written
- # to filehandle MACRO.
- # This subroutine is almost the same as PointsMacro; differences are: different
- # arrays and array indeces; not plotting "Point at the pole"; only two pens used;
- # and there is no check for whether the variable is defined.
-
- my ($m, $p, $i, $s, $c);
- $s = 'PT Period Pen = #';
- print MACRO ("\#Major = 9\r\#Minor = 12\r"); # Pen variables
- foreach $m (0 .. 45) {
- if ($m % 5 == 0) {
- $c = 'Major'; # Major meridian
- } else {
- $c = 'Minor'; # Minor meridian
- }
- foreach $p (0 .. 3) {
- $i = $m . "," . $p ;
- print MACRO ($s,$c,' ', Coordinate($xJ{$i},$yJ{$i}), '[`;`]', "\r" );
- }
- }
- } # End of subroutine JointsMacro.
-
-
- sub MeridianMacro {
- # I will be lazy and use global variables instead of trying to pass hashes as
- # parameters.
- # It is assumed that every meridian multiple of 5 will be written to file MAJOR;
- # other meridians are written to file MINOR; Meridian numbers are from 0 to 45;
- # will use hashes %xJ and %yJ, each of which is indexed as "i,j", where i= 0 .. 45,
- # and j = 0 .. 4, for start polar point, two joints and equator point.
- my ($m, $M, $s, $FileHandle);
- foreach $m (0 .. 45) {
- $M = $m . ',' ;
- if ( ($m % 5) == 0 ) { # Major meridian
- $FileHandle = MAJOR;
- } else { # Minor meridian
- $FileHandle = MINOR;
- }
- print $FileHandle ('LI ', Coordinate($xJ {$M . 0}, $yJ {$M . 0})); # First point
- for ($s = 1; $s <= 3; $s++ ) { # for each line segment
- print $FileHandle ("\\\r",Coordinate($xJ {$M . $s},$yJ {$M . $s}) );
- } # End of doing one meridian with 3 segments
- print $FileHandle ('[`;`]', "\r"); # End drawing of this multi-line
- } # End of for(m)-loop
- } # End of Subroutine MeridianMacro
-
- sub ParallelArcs {
- # This subroutine expects first and last parallels to do, and start and end meridians
- # for the circular arc. If there is a 5th argument, it is a string to append to
- # the comment line at the start of each parallel (e.g. ", Octant 1 West").
- # It is assumed that centre of circle is point A, with global coordinates $xA, $yA.
- # I will be lazy and use global variables instead of trying to pass hashes as
- # parameters. Will use hashes %xP and %yP, each of which is indexed as "m,p".
- # It is assumed that every parallel multiple of 5 will be written to file MAJOR;
- # other meridians are written to file MINOR.
- my ($m, $p, $P, $FileHandle, $pStart, $pEnd, $mStart, $mEnd, $Memo);
- ($pStart, $pEnd, $mStart, $mEnd, $Memo) = @_;
- if (not defined($Memo) ) {$Memo = "";}
-
- # Make sure start is less than end, to be able to use foreach
- if ($pStart > $pEnd) {
- $pStart = $pEnd; $pEnd = $_[0];
- }
- foreach $p ($pStart .. $pEnd) {
- $P = ',' . $p ;
- if ( ($p % 5) == 0 ) { # Major parallel
- $FileHandle = MAJOR;
- } else { # Minor parallel
- $FileHandle = MINOR;
- }
- print $FileHandle ('{ Parallel ', $p, $Memo,' }', "\r");
- print $FileHandle ('AR ', Coordinate ($xA, $yA), "\\\r");
- print $FileHandle (Coordinate ($xP {$mStart . $P}, $yP {$mStart . $P}) );
- print $FileHandle (Coordinate ($xP {$mEnd . $P}, $yP {$mEnd . $P} ) );
- print $FileHandle (' [`;`]', "\r");
- }
- } # End of subroutine ParallelArcs
-
-
-
- sub ParallelMacro {
- # This subroutine expects first and last parallels to do, and start and end meridians
- # for the segmented parallel. If there is a 5th argument, it is a string to append to
- # the comment line at the start of each parallel (e.g. ", Octant 1 West").
- # I will be lazy and use global variables instead of trying to pass hashes as
- # parameters. Will use hashes %xP and %yP, each of which is indexed as "m,p".
- # It is assumed that every parallel multiple of 5 will be written to file MAJOR;
- # other parallels are written to file MINOR.
- my ($m, $p, $P, $FileHandle, $pStart, $pEnd, $mStart, $mEnd, $Memo, $mS, $mE);
- ($pStart, $pEnd, $mStart, $mEnd, $Memo) = @_;
- if (not defined($Memo) ) {$Memo = "";}
-
- # Make sure starts are less than ends, to be able to use foreach
- if ($pStart > $pEnd) {
- $pStart = $pEnd; $pEnd = $_[0];
- }
- if ($mStart > $mEnd) {
- $mStart = $mEnd; $mEnd = $_[2];
- }
- $mS = $mStart + 1; $mE = $mEnd - 1;
-
- # For each parallel to be done
- foreach $p ($pStart .. $pEnd) {
- $P = ',' . $p ;
- if ( ($p % 5) == 0 ) { # Major parallel
- $FileHandle = MAJOR;
- } else { # Minor parallel
- $FileHandle = MINOR;
- }
- print $FileHandle ('{ Parallel ', $p, $Memo, ' }', "\r");
- # Start point of line
- print $FileHandle ('LI ', Coordinate ($xP {$mStart . $P}, $yP {$mStart . $P} ) );
- foreach $m ($mS .. $mE) { # For each meridian
- print $FileHandle ("\\\r", Coordinate ($xP {$m . $P}, $yP {$m . $P} ) );
- if (($m % 15) == 0) {
- # Every 15 segments or so, terminate and restart line command
- print $FileHandle ('[`;`]', "\rLI ",
- Coordinate ($xP {$m . $P}, $yP {$m . $P} ) );
- }
- } # End of foreach meridian
- # Last point of parallel
- print $FileHandle (Coordinate ($xP{$mEnd.$P}, $yP{$mEnd.$P}), '[`;`]', "\r");
- } #End of foreach parallel
- } # End of subroutine ParallelMacro
-
- sub ParallelMacro5 {
- # This subroutine expects first and last parallels to do, and start and end meridians
- # for the segmented parallel. It draws line segments for parallels by connecting nodes
- # of major meridians, that is, every 5th meridian, skipping in between nodes.
- # If there is a 5th argument, it is a string to append to the comment line at the start
- # of each parallel (e.g. ", Octant 1 West").
- # I will be lazy and use global variables instead of trying to pass hashes as
- # parameters. Will use hashes %xP and %yP, each of which is indexed as "m,p".
- # It is assumed that every parallel multiple of 5 will be written to file MAJOR;
- # other meridians are written to file MINOR.
- # This subroutine writes one parallel per LINE command (5° times 9 segments=45°).
-
- my ($m, $p, $P, $FileHandle, $pStart, $pEnd, $mStart, $mEnd, $Memo, $mS, $mE);
- ($pStart, $pEnd, $mStart, $mEnd, $Memo) = @_;
- if (not defined($Memo) ) {$Memo = "";}
-
- # Make sure starts are less than ends, to be able to use foreach
- if ($pStart > $pEnd) {
- $pStart = $pEnd; $pEnd = $_[0];
- }
- if ($mStart > $mEnd) {
- $mStart = $mEnd; $mEnd = $_[2];
- }
- $mS = $mStart + 1; $mE = $mEnd - 1;
-
- # For each parallel to be done
- foreach $p ($pStart .. $pEnd) {
- $P = ',' . $p ;
- if ( ($p % 5) == 0 ) { # Major parallel
- $FileHandle = MAJOR;
- } else { # Minor parallel
- $FileHandle = MINOR;
- }
- print $FileHandle ('{ Parallel ', $p, $Memo, ' }', "\r");
- # Start point of line
- print $FileHandle ('LI ', Coordinate ($xP {$mStart . $P}, $yP {$mStart . $P} ) );
- foreach $m ($mS .. $mE) { # For each meridian
- if (($m % 5) == 0) { # only do for major meridians
- print $FileHandle ("\\\r", Coordinate($xP{$m.$P},$yP{$m.$P} ) );
- }
- } # End of foreach meridian
- # Last point of parallel
- print $FileHandle (Coordinate ($xP{$mEnd.$P}, $yP{$mEnd.$P}), '[`;`]', "\r");
- } #End of foreach parallel
- } # End of subroutine ParallelMacro5
-
- sub MLinesMacro {
- # Macro to draw concatenated lines, with coordinates from different octants.
- # First argument is file handle. The second argument must be a number:
- # If it is 0, the following arguments are sets of x,y, and octant number.
- # If it is a number between 1 and 8, that is the number of the octant for all
- # subsequent pairs of x,y coordinates.
- # All coordinates are converted to M-map system.
- my ($FileHandle,$Octant, @a) = @_ ;
- my ($nArg, $i,$x,$y,$x2,$y2,$n);
- $nArg = @a - 1;
- $n = 0; # Flag for starting point
- if ($Octant == 0) {
- for ($i = 0; $i < $nArg; $i=$i+3) {
- ($x2,$y2) = MJtoG ($a[$i], $a[$i+1], $a[$i+2]);
- if ($n == 0) { # Starting point; update flag
- print $FileHandle ('LI ', Coordinate ($x2,$y2) );
- $n ++ ;
- } else {
- # Do line continuation, and this point
- print $FileHandle ("\\\r",Coordinate ($x2,$y2) );
- }
- }
- } else {
- for ($i = 0; $i < $nArg; $i=$i+2) {
- ($x2,$y2) = MJtoG ($a[$i], $a[$i+1], $Octant);
- if ($n == 0) { # Starting point; and update flag
- print $FileHandle ('LI ', Coordinate ($x2,$y2) );
- $n ++ ;
- } else {
- # Do line continuation, and this point
- print $FileHandle ("\\\r",Coordinate ($x2,$y2) );
- }
- }
- }
- print $FileHandle (' [`;`]', "\r");
- } # End of subroutine MLinesMacro
-
- sub OctantMacro {
- # Macro to draw concatenated lines. Being lazy and using global arrays
- # @xOct and @yOct, and writing to file handle MACRO.
- my ($FileHandle,@x, @y, $n, $i);
- $FileHandle = MACRO;
- @x = @xOct; @y = @yOct;
- $n = @xOct - 1;
- print $FileHandle ('LI ', Coordinate ($x[0],$y[0]) );
- foreach $i (1 .. $n) {
- # Do line continuation, and this point
- print $FileHandle ("\\\r",Coordinate ($x[$i],$y[$i]) );
- }
- print $FileHandle (' [`;`]', "\r");
- } # End of subroutine LinesMacro
-
- sub GridMacro {
- # Arguments are: filehandle, left, right, bottom, top, spacing, spacing of next
- # larger grid or 0 to not skip major lines.
- # Notice: every $skip line is not plotted; it will be part of the grid of next larger size.
- my ($filehandle, $left, $right, $bottom, $top, $delta, $skip) = @_ ;
- my ($i, $a, $b, $c);
- $a = 'LI [a,';
- $b = ',0,` `] [a,';
- $c = ',0,` `] [`;`]' . "\r";
- $i = $bottom;
- # If bottom is not a multiple of delta, start plotting at the first multiple of delta
- if ($i % $delta !=0) { $i = $i + $delta - ($i % $delta); }
- print $filehandle '{ Horizontal lines }', "\r" ;
- while ($i <= $top) { # horizontal lines
- if ($skip != 0 && $i % $skip == 0) {
- $i = $i + $delta;
- next;
- }
- print $filehandle $a,$left,',',$i,$b,$right,',',$i,$c;
- $i = $i + $delta;
- }
- $i = $left;
- # If left is not a multiple of delta, start plotting at the first multiple of delta
- if ($i % $delta !=0) { $i = $i + $delta - ($i % $delta); }
- print $filehandle '{ Vertical lines }', "\r" ;
- while ($i <= $right) { # vertical lines
- if ($skip != 0 && $i % $skip == 0) {
- $i = $i + $delta;
- next;
- }
- print $filehandle $a,$i,',',$top,$b,$i,',',$bottom,$c;
- $i = $i + $delta;
- }
- } # End of subroutine GridMacro
-
- sub LandMacro {
- # Will be lazy and read global arrays @Xs and @Ys, and write to filehandle LAND.
- my ($nPoints, $FileHandle, $n);
- $nPoints = @Xs - 2;
- $FileHandle = LAND;
- print $FileHandle ('LI ', Coordinate ($Xs [0], $Ys [0]) );
- foreach $n (1 .. $nPoints) {
- print $FileHandle ("\\\r", Coordinate ($Xs[$n], $Ys [$n] ) );
- if (($n % 15) == 0) {
- # Every 15 segments or so, terminate and restart line command
- print $FileHandle ('[`;`]', "\rLI ", Coordinate ($Xs[$n], $Ys [$n] ) );
- }
- }
- print $FileHandle (Coordinate ($Xs[$nPoints+1], $Ys[$nPoints+1]), '[`;`]', "\r");
- } # End of subroutine LandMacro
-
- # - - - - - - - - - SUBROUTINES For Coordinate conversion - - - - - - - - - - - -
-
- sub MJtoG {
- # Subroutine to convert (that is, do coordinate transformation of) x and y coordinates
- # from Mary Jo's half-octant on its side to Gene's leaning, single octant coordinates, or
- # to Gene's M-map (eight-octants) coordinates.
- #
- # Subroutine returns converted x and y coordinates.
- #
- # Arguments are:
- # - x and y coordinates of point to convert.
- # - Third argument, if given, is the Octant to convert to:
- # - no argument or 0 – Gene's single-octant system, with y-axis on its left;
- # - 1, 2, 3 or 4 – convert to M-map coordinates, respectively to first, second, third or
- # fourth northern octant, from the left;
- # - 5, 6, 7 or 8 – convert to M-map coordinates, respectively to fourth, first, second or
- # third southern octant from the left.
- #
- # - In MJ's coordinates, point M is the origin, at (0,0), points M, A and G are on the positive
- # x-axis, and point G is at (10000, 0).
- # - In G's system, point M, L, J and P are on the positive y-axis, and point G is on the positive
- # x-axis; in this system, point G is at coordinates (5000, 0).
- # - From MJ's system to G's, there is a +60° rotation, and also a translation.
- # - The M-map coordinate system is like G's system, except that the y-axis is 10000mm
- # to the right, that is, the x-coordinates for the start octant are 10000mm smaller.
- #
- # I got the equations for rotation and translation from my pocketbook "The Universal
- # Encyclopedia of Mathematics, with a Foreword by James R. Newman", Š1964 by
- # George Allen and Unwin, Ltd.; translated from original German language edition,
- # pages 152, 153.
- #
- # This subroutine, in order to not have to recompute them each time the routine is called,
- # uses a few global variables from the main program:
- # $cos60 = cos (deg2rad(60));
- # $sin60 = sin (deg2rad(60));
- # $yTranslate = 10000 * $sin60;
-
- my ($nArgs, $xnew, $ynew);
- my ($x, $y, $Octant) = @_ ;
- if (not defined ($Octant) ) { $Octant = 0; }
- if ($Octant == 0) {
- ($xnew, $ynew) = Rotate ($x, $y, 60);
- } elsif ($Octant == 1) {
- ($xnew, $ynew) = Rotate ($x, $y, 120);
- $xnew = $xnew - 10000;
- } elsif ($Octant == 2) {
- ($xnew, $ynew) = Rotate ($x, $y, 60);
- $xnew = $xnew - 10000;
- } elsif ($Octant == 3) {
- ($xnew, $ynew) = Rotate ($x, $y, 120);
- $xnew = $xnew + 10000;
- } elsif ($Octant == 4) {
- ($xnew, $ynew) = Rotate ($x, $y, 60);
- $xnew = $xnew + 10000;
- } elsif ($Octant == 5) {
- ($xnew, $ynew) = Rotate ((20000-$x), $y, 60);
- $xnew = $xnew + 10000;
- } elsif ($Octant == 6) {
- ($xnew, $ynew) = Rotate ((20000-$x), $y, 120);
- $xnew = $xnew - 10000;
- } elsif ($Octant == 7) {
- ($xnew, $ynew) = Rotate ((20000-$x), $y, 60);
- $xnew = $xnew - 10000;
- } elsif ($Octant == 8) {
- ($xnew, $ynew) = Rotate ((20000-$x), $y, 120);
- $xnew = $xnew + 10000;
- } else {
- print "Error converting to M-map coordinates; there is no $Octant octant!\n";
- return ($x,$y);
- }
- $ynew = $ynew + $yTranslate;
- return ($xnew, $ynew);
-
- } # End of subroutine MJtoM, which converts coordinates to octants on M-map
-
- sub Rotate {
- # Receives 3 arguments: x, y, and angle by which to rotate the coordinate system;
- # Expects that the axes will be rotated either 60° or 120°.
- # Returns new x and y values.
- # Uses $cos60, $sin60 global variables from main program, to minimize computations.
- my ($x, $y, $angle) = @_ ;
- my ($xnew, $ynew);
- if ( $angle == 60 ) {
- $xnew = $x * $cos60 + $y * $sin60;
- $ynew = -$x * $sin60 + $y * $cos60;
- } elsif ( $angle == 120 ) {
- $xnew = -$x * $cos60 + $y * $sin60;
- $ynew = -$x * $sin60 - $y * $cos60;
- }
- return $xnew, $ynew;
- } # End of subroutine Rotate
-
- sub Real2Map {
- # Arguments are real world longitude and latitude for one point, in decimal degrees.
- # West longitudes and south latitudes have negative values.
- # Returns x and y values in M-Map coordinates.
- #
- # Subroutine uses the following global variables, without modifying them:
- # $DeltaMEq, $EF, $AG, $xA, $yA, $xE, $yE, $xF, $yF, $xG, $xM, $yM.
- # Also, it calls subroutines LineIntersection, Length, Interpolate and MJtoG.
-
- # @South are southern octants corresponding to northern octants 1, 2, 3 and 4; the 0
- # is just a place holder to facilitate correspondence.
- my (@South) = (0,6,7,8,5);
- # $m and $p are the meridian and parallel numbers in scaffold half-octant setting;
- # $Octant is the M-map octant of the real point; $Sign is for east or west side of
- # scaffold octant; $x and $y are coordinates in scaffold half-octant setting; $xNew
- # and $yNew are the coordinates converted to M-Map system, which are returned.
- my ($Octant, $m, $p, $Sign, $x, $y, $xNew, $yNew);
- # Local arrays @xJ, @yJ and @L are equivalent to the global hashes %xJ, %yJ, %L,
- # but just for this particular meridian. The other variables are temporary.
- my (@xJ, @yJ, @L, $distance, $extra, $flag);
- # Input values
- my ($Long, $Lat) = @_ ;
- # Determine the correct octant; Octant 1 is +160° to -110°; octant 4 is 70° to 160°
- $Octant = int ( ($Long + 200) / 90 ) + 1;
- # Make longitude fit within scaffold/template triangle, and determine if y value should
- # be positive or negative.
- $m = ( ($Long +200) - (90*($Octant - 1))) - 45;
- if ($m < 0) {
- $Sign = -1; $m = -$m;
- } else {
- $Sign = 1;
- }
- # Fix the octant number, if necessary
- if ($Octant == 5) { $Octant = 1; }
- if ($Lat < 0) {
- $Octant = $South [$Octant];
- $p = -$Lat;
- } else {
- $p = $Lat;
- }
- # print "$Long, $Lat convert to $m, $p, $Sign, $Octant.\n";
- # Now need to calculate x and y coordinates for $m,$p in scaffold triangle.
- if ($m == 0) { # Centre line meridian is straight, and easy to calculate
- $y = 0;
- $x = $xG - $p * $AG / 90;
- } else { # Complicated jointed meridian
- # Calculate coordinates of joints
- $xJ [0] = $xA; $yJ [0] = $yA; # Polar end of meridian
- $distance = $m * $DeltaMEq;
- # Equatorial end of meridian
- if ($distance <= $yF) {
- $xJ [3] = $xG;
- $yJ [3] = $distance;
- } else { # Past joint at point F
- $extra = $distance - $yF;
- $xJ [3] = Interpolate ($extra, $EF, $xF, $xE);
- $yJ [3] = Interpolate ($extra, $EF, $yF, $yE);
- }
- # Calculate joints by line intersection from A and M
- ($flag, $xJ [1], $yJ [1]) = LineIntersection ($xM, $yM, 2*$m/3, $xA, $yA, $m);
- if ($flag ne "Intersect") { die "$flag while calculating 1st joint at $m.\n"; }
- ($flag, $xJ [2], $yJ [2]) =
- LineIntersection ($xM, $yM, 2*$m/3, $xJ [3], $yJ [3], $m/3);
- if ($flag ne "Intersect") { die "$flag while calculating 2nd joint at $m.\n"; }
- # Calculate length of meridian segments.
- $L [0] = Length ($xA, $yA, $xJ [1], $yJ [1]);
- $L [1] = Length ($xJ [1], $yJ [1], $xJ [2], $yJ [2]);
- $L [2] = Length ($xJ [2], $yJ [2], $xJ [3], $yJ [3]);
- $L [3] = $L [1] + $L [2]; # Torrid + Temperate
- $L [4] = $L [3] + $L [0]; # Total meridian length
- # Calculate parallel intersection – location of this latitude on this meridian
- $distance = $p * $L [4] / 90; # total length corresponds to 90°
- if ($distance <= $L [2] ) { # Torrid segment
- $x = Interpolate ($distance, $L [2], $xJ [3], $xJ [2]);
- $y = Interpolate ($distance, $L [2], $yJ [3], $yJ [2]);
- } elsif ($distance <= $L [3] ) { # Temperate seg., past one joint
- $extra = $distance - $L [2];
- $x = Interpolate ($extra, $L [1], $xJ [2], $xJ [1]);
- $y = Interpolate ($extra, $L [1], $yJ [2], $yJ [1]);
- } else { # Frigid segment, past two joints
- $extra = $distance - $L [3];
- $x = Interpolate ($extra, $L [0], $xJ [1], $xJ [0]);
- $y = Interpolate ($extra, $L [0], $yJ [1], $yJ [0]);
- }
- } # Now have $x and $y coordinates in scaffold half-octant coordinates
- # Convert to M-map coordinates
- ($xNew, $yNew) = MJtoG ($x,$Sign*$y, $Octant);
- # print "and x,y: $x, $y, converted to $xNew, $yNew.\n";
- return $xNew, $yNew;
- } # End of subroutine Real2Map
-
- # - - - - - - - - - SUBROUTINES - - - - - - - - - - - - -