The magazine of the Melbourne PC User Group

Do your block
Ken Holmes
kholmes@melbpc.org.au

A fellow member who owns a block of land with no fewer than eight sides was curious to know exactly the extent of his claim to this planet. It seemed like a nice programming exercise, so here it is. Your title deed provides the length of each side and its compass bearing. Whilst most blocks have at least one pair of parallel sides, even these often vary by a few minutes of arc. By division into the odd rec tangle and triangle you can usually get the area fairly accurately, but we will do a more generalised solution by dividing into all triangles, i.e. if there are n sides we need n - 2 triangles. The QuickBasic code should be self explanatory, armed with the fact that the area of a triangle is given by
Area = 0.5 x side1 x side2 x sin(included angle)

The result is presented graphically so that you will see readily if you have sent one side off on the reciprocal bearing or, if the polygon does not close accurately, there may be an error on your title deed, not unknown to happen. It doesn't matter where you start but if you go anticlockwise you'll get a negative area, which doesn't matter either.

With a complicated shape, if the bearing (from the starting point) to one point swings back anticlockwise, relative to the bearing to the previous point, a negative triangle area will be printed, but this will not faze the trigonometry and the total area will be correct. LANDAREA.LZH can be downloaded, containing the .EXE and .BAS files, written in QuickBasic but suitable for QBasic.

As usual, my apologies to "real" programmers who are offended by my, self-taught, bad habits, having never been subject to the discipline of team programming. My defence is that I am enjoying myself and the program works; I hope it may encourage young amateurs to write more programs and young professionals to rectify shortcomings in format, error checking, presentation, etc.

It's only vaguely related, but why should that stop me? We all like a good disaster story, don't we? In 1966, by the Swan River, Perth, the local purveyor of milk, aspiring to become my neighbour, commissioned the erection of a magnificent pile. It would be complete with magnificent "double garage under", nestling comfortably 5 feet into the accommodating sandy riverside soil and providing enhanced river views from the elevated domicile. Must have been good money in milk in those days!

A couple of weeks saw the excavation, concreting of garage floor and erection of brick walls with house floor joists proceeding at a merry pace. They didn't mess about in the building trade. The block tapered to the back fence and was a mirror image of that of my immediate neighbour, a nice, older gentleman, as I am now - well I'm older. Said nice, etc, expressed to me one day his apprehension that they were transgressing the boundary of the adjacent, vacant block. It didn't need a theodolite to see he was dead right.

As a recent land purchaser, I had the subdivision plan which showed their mutual back fence to be 65, that is 65 links. The draughtsman in his cosy office, somewhat removed from the scene, must have taken this as 65 feet, which it ain't - more like 48' 9" - but which considerably eased the positioning of the magnificent pile on the constricted area. Ah, the joys of multiple systems of units. I won't metricate this story. Naturally, I considered the timing to be right for a discreet call to the builder and the answering lady undertook to relay the message. I daresay they might have had an impulse to shoot the messenger, but they didn't track me down with a box of chocolates for my helpful observation.


Figure 1 An 80 x 40 block with a 40 x 5 "hole"


Figure 2 A 10-acre block using deed measurements (in metres)

After an intermission of a few weeks, operations resumed with an amount of de-erection and an amount of filling in of a big hole, partly on someone else's property, or property-to-be. We now had a magnificent "1.5 garage under", nestling, etc (at least, comfortably for the moment) and prospects of a dinky little triangular kitchenette in lieu of the planned sumptuous food preparation area. Having been a diligent supervisor of the construction of my own humble abode, I gave his builders 9/10 for execution and 5/10 for planning. The owner had to wear 4/10 for paying attention; he must have considered it more important to tend to the efficiency of his milk distribution system.

In due course, a house warming was conducted, super woofers and all, which confirmed the transmission coefficients of the local atmosphere and the well compacted sandy soil. Whilst not invited, I "experienced" the jollity (methinks there was something in the milk) and my sympathies for my new neighbour waned a little. However, they were re-established during the following wet season, and all subsequent such, when the water table rose giving him a 3-foot deep swimming pool in the basement, not recommended for storage of your 1.5 Mercedes Benzes - interferes with the ignition or something. (Sorry, couldn't resist the embellishment. I don't really remember the marque of his transport.)
 

'The main module
DECLARE SUB Getdata ()
DECLARE SUB Result ()
'we need some global variables/arrays
DIM SHARED numpts AS INTEGER, Area(10)
DIM SHARED Coordx(10), Coordy(10)
DIM SHARED Bearone(10), Bearlast(10)
DIM SHARED Distone(10), Distlast(10)
Start:           'let's do it
Getdata        'input the data
Result           'print graphical solution
END              'tata

SUB Getdata
CLS 'clean the slate
pi = 3.141593: radconv = pi / 180
PRINT " If you have an irregular polygon, such as a block of land, with n"
PRINT " sides and have the length of each side and its direction,the area"
PRINT " can be found by dividing it into n - 2 triangles.":
PRINT
PRINT " Choose your first point then enter the data as requested. If you"
PRINT " proceed clockwise, the area will be positive, or anticlockwise"
PRINT " will be negative. Land titles give direction from 0 to 180 degrees"
PRINT " but, if you are going in a westerly direction, add 180 to give the"
PRINT " true bearing.": PRINT
INPUT " Enter the total number of points                  ";numpts
FOR i = 2 TO numpts + 1 'Point (numpts+1) is the same as Point 1 and we...
          '...need some modular arithmetic to handle this.
   p1 = (i - 2) MOD numpts + 1: p2 = (i - 1) MOD numpts + 1
   PRINT " Enter bearing FROM point"; p1; "TO point";
   p2; " , degrees ";
   INPUT Bearlast(i)
   PRINT " ,
   minutes ";
   INPUT mins
   Bearlast(i) = (Bearlast(i) + mins / 60) * radconv
   PRINT " Enter (decimal) distance from point"; p1;"to point "; p2;
   INPUT Distlast(i)
   Coordx(i) = Coordx(i - 1) + Distlast(i) * SIN(Bearlast(i))
   Coordy(i) = Coordy(i - 1) + Distlast(i) * COS(Bearlast(i))
   IF i = 2 THEN 'for first side only
      Bearone(2) = Bearlast(2): Distone(2) = Distlast(2)
   ELSE 'for others call for Pythagoras
     Distone(i) = SQR(Coordx(i) * Coordx(i) + Coordy(i) * Coordy(i))
     IF i numpts + 1 THEN      'excepting last side. Avoid divide by zero.
       IF ABS(Coordy(i)) .0000001 THEN Coordy(i) = .0000001
       Bearone(i) = ATN(Coordx(i) / Coordy(i))      'Bearing from point 1
       IF Coordy(i) 0 THEN Bearone(i) = Bearone(i) + pi
       Area(i)= .5 *Distone(i) *Distone(i-1) *SIN(Bearone(i)-Bearone(i-1))
       PRINT " Area of triangle no. "; i - 2; " = "; Area(i)
     END IF
   END IF
NEXT i
END SUB

SUB Result
SCREEN 12: VIEW: VIEW PRINT: CLS 'VGA screen
xmax = 0: xmin = 0: ymax = 0: ymin = 0      'zero limits at point 1
FOR i = 2 TO numpts             'find extent to be fitted into screen
   IF Coordx(i) xmax THEN xmax = Coordx(i)
   IF Coordx(i) xmin THEN xmin = Coordx(i)
   IF Coordy(i) ymax THEN ymax = Coordy(i)
   IF Coordy(i) ymin THEN ymin = Coordy(i)
NEXT i
ratio=.75 *(xmax - xmin) /(ymax - ymin)      'screen 4 wide & 3 high
IF ratio 1 THEN                               'must fit into screen width
   average=(xmin + xmax)/2: range=.55 *(xmax-xmin)   '+10% on sides
   left = average - range: right = average + range
   average = (ymin + ymax) / 2: range = .55 * (ymax-ymin) * ratio
   bottom = average - range: top = average + range
ELSE            'must fit into screen height
   average=(ymin+ymax)/2:range=.55*(ymax-ymin)    '+10% top & bottom
   bottom = average - range: top = average + range
   average = (xmin + xmax) / 2: range = .55 * (xmax-xmin) / ratio
   left = average - range: right = average + range
END IF
WINDOW (left, bottom)-(right, top)        'set window size to fit
FOR i = 3 TO numpts: LINE(0,0)-(Coordx(i), Coordy(i)), 4: NEXT i
FOR i = 1 TO numpts
   LINE (Coordx(i), Coordy(i))-(Coordx(i + 1), Coordy(i + 1))
NEXT i
Total = 0: FOR i = 3 TO numpts: Total = Total + Area(i): NEXT i
LOCATE 10, 20: PRINT "Closure gap = ";
PRINT USING "#####.##"; Distone(numpts + 1)
LOCATE 12, 20: PRINT "If large, query data."
LOCATE 14, 20: PRINT "Total area = "; Total
FOR i = 1 TO numpts                           'number the points on graph
   Loc1 = 30*(top-Coordy(i))/(top-bottom)
   Loc2 = 80*(Coordx(i)-left)/(right-left)
   LOCATE Loc1, Loc2 : PRINT i : NEXT i
DO: LOOP WHILE INKEY$ = ""                'Any key ends
END SUB

Reprinted from the February 1999 issue of PC Update, the magazine of Melbourne PC User Group, Australia

[About Melbourne PC User Group]