This page throws down a challenge: Can you write the program I need? It follows on from "Part 1".
There wasn't a lot of programming in achieving the first stage of completing the challenge... but there was some tedious mathematics to grasp. This second part will be more challenging on the programming front. All the "mathematics" is behind us!
You can download the sourcecode of the shell for the program.
Here's a reminder of the first challenge...
Suppose I give you the coordinates of three points on a surface....
If you draw lines, as above, three points define an angle.
The challenge? Write a subroutine to calculate the angle from the coordinates of the points.
For the first part, you were promised...
Now only the first two promises remain. Dropping the second two mean that the angle can be "pointing" almost anywhere.
The second challenge can be tackled in two stages, which I will call "2a" and "2b". The completion of 2a will still look like...
The six numbers (70, 30, 10, 20, 40 and 30) are the coordinates of the three points. They go in edit boxes. (Or, if you would rather, a small text file.. but if you use that method, and read the text file as part of the DoIt handler, copy the 6 values to the screen, so it looks like the screenshot anyway.)
The screenshot (from a mock up of the application that you are challenged to create) shows what the window should look like AFTER the "Do It" button has been clicked.
(The answer, by the way is almost certainly NOT 20.7 !! That is only approximately right! (It was put into the image with a kludge before I knew the exact answer.))
So! You know what the screen should look like.
The code should still be structured to use a subroutine to calculate the angle.
Here's a sketch of the OnClick handler for the button captioned "Do It"....
procedure TLDN185f1.buDoItClick(Sender: TObject); var rAns:real; x0,y0,x1,y1,x2,y2:integer; begin //(fill x0, y0, x1, etc with the values you // want to do the calculation for) rAns:=rAngleFromCoords(x0,y0,x1,y1,x2,y2); laAns.caption:=floattostr(rAns); end;
I hope that these challenges will be assigned as homework for a class learning to program. They have been structured to take you through a programming project along a "good" path... the program is build incrementally. In part 1, we established a framework which would serve for parts 2a and 2b, as well.)
If you only find Challenge 2b interesting, by all means tackle that, and have it output the coordinates of the three points defining the angle.
Here's what the subroutine looks like early in the development process...
function TLDN185f1.rAngleFromCoords(x0,y0,x1,y1,x2,y2:integer):real; begin result:=20.7; end;
(Yes: The program has two x0's, two y0's, etc. The wonders of "scope" make that okay.)
If submitting your creation for "world fame" via this site, please KEEP the elements present in the "sketch" above, e.g. the variable names and what part of the application was broken out into the subroutine.
Use the same variables, and variable types, in the definition of the subroutine.
On the left: A reminder of the basic problem. Given three sets of coordinates, calculate the size of the angle in degrees.
But what if the constraints which applied in Part 1 of the challenge are relaxed? Then the angles on the right become possible. (Including the 90 degree angle, "turned" like that, which could be a nuisance case the programmer may need to accommodate with some special code.)
And finally, there is the matter illustrated on the left.
Every angle, for the purposes of the challenge, is to be measured "counter-clockwise" (see illustration) from the side defined by x0, y0 (look closely at the text in the illustration.)
So angle "A" is about 90 degrees, and angle "B" is about 270 degrees.
The same way you did things in Part 1 of the challenge!
With some new stuff.
You still start by "sliding" (transposing) the angle to put the vertex on the origin of the coordinates. (I.e: To put the apex of the angle at "0,0")
But... what if?.... what if that results in something like the following, and you are being asked the size of the green angle, angle "A"?
Not a (big) problem!
You just break the angle up into bits you can do!
Angle "B" is easy... you've done angles like this before.
Angle "C" isn't too hard. When you have "B" and "C", add those numbers together and that's "A"!
To get C directly, you just "flip things around". Or you may prefer to flip things to solve for D. 90-D will give you C... won't it?! (^_^)
I've restricted my use of arctan to "simple" triangles, contained within the quadrant from angle= 0 to angle= 90. It IS possible to use it with other angles, but i am a bear of limited brain, and prefer to do things "the hard way" (e.g. by flipping the angles about, and using "tricks" like the one described earlier.) If your grasp of trig is better than mine, there may be things you can do to save yourself some of the hassle I would endure, were I to do this programming.
The hard part is going to be writing the code to make your application analyze the particular question that has been presented, via the three sets of coordinates, and "decide" which type of problem it is, so that it can go off and solve the problem by the steps appropriate to that type of problem.
It may be helpful to start by characterizing each of arms with a "code" from 0-7, as implied in the diagram.
The good news? All of it will "boil down" to using the function we have already made, in Part 1 of the challenge.
Please don't be "shy"... successes with "only" part 2a of the challenge would be of interest. If you help me with "camera ready" material, I would be glad to showcase what you have done, here.
Please understand: Part (only part) of the reason for creating this page was to get someone else to do the programming for me. (Just doing it myself would have been much less work than doing this page!)... I will assume that you are "giving away ALL your rights" to any code you submit for celebration here. I might well publish it. I, and others, may produce derivative works, and will point to this, if you ask for any payment. I will give you credit, on some level, if I use your stuff. I can't promise that others will.
Hurrah! We've got the core of a useful application in place. We have the subroutine for calculating a broad class of angles.
I wanted that to use at the heart of a specific application.
In a different challenge I've put elsewhere on the web, organizers set something like this up in a large space, e.g. a school gym. (The challenge is to do with making maps by triangulation.)
The blue letters (A, B, C...) are marks on the floor. The magenta letters (Z, Y, X, W...) are masking tape crosses on the room's walls.
The challenge participants try to measure as many of the angles present as the can. The participants have to stay on the AC and AE lines; they can't go to where the crosses on the walls are. (The illustration shows a few sample angles: YDV, ZAX, ZAU, XAU)
The application I hope to provide one day would read a small text file and then generate a table of all the angles present in the room.
The text file would hold various measurements from the room... measurements made by the challenge organizers. (The challenge participants will be operating on the premise that they can't get to Z, Y, X, etc.... just as the surveyors who first measured Everest were not able to get close to the mountain.
... and from it create a table like the following, with numbers where I've put "nnn".
The application would be "told" by the text file how many sighting stations (A, B, C...) and how many targets (Z, Y, X, W...) were in use in the instance in question.
For a situation where A-E and V-Z are in use, the output would look like... leaving out the things in ( )s, which are just explanations.
ZEC=nnn ZEB=nnn ZEA=nnn === ZDC=nnn ZDB=nnn ZDA=nnn === ZCB=nnn (no need to do ZCA.. same as ZCB. Similar equivalents should also be dropped) === YEC=nnn YEB=nnn YEA=nnn ======= YDC=nnn YDB=nnn YDA=nnn === ....(and so on!!!)
In order to make creating the text file easier, and agree some variable names to be used, please, by anyone attempting this challenge, here's an overview of a specific instance of "the arena"
A-F are the "stations" from which participants measure angles. Thus they are also where the apex of the angle will be. The break into two sets, with one of them, "C", in this instance, a member of both sets.
Remember: Elsewhere it was stipulated that lines of stations and targets are either parallel or perpendicular to other such lines.
Note: There must be a station "on the corner", where the line of stations "bends". In this case, "C" fulfills that requirement. Likewise, there must be a target where the line of targets bends. In this case "X" is that station.
If it is hard to put a target where the line bends, don't worry about it. You need to "pretend" there is one there, even if there's no actual target for participants to use to define one of the arms of the angle.
(The "station/ target" at corner requirement is to do with telling the application where the stations/ targets are, so that it can calculate the angles.)
A "brute force" "solution" would be to simply plow through all of the stations and targets, and report their coordinates.
However, because of the "parallel or perpendicular" rule, the whole business can be made more efficient. The stations A-C all have the same X coordinate, for instance.
Names: I've called stations A-C the "NSStations", because, if you treat the map as showing a room with north at the top, these stations create a line which runs from north to south. Similar logic determines other names.
Inside the application's code, there should be a two arrays... iXSta[0..n] and iYSta[0..n]. They will hold the coordinates of the stations. In type- integer variables. The coordinates of station A would go in iXSta and iYSta. (Yes, you could put the values in one record-type array, with two elements per index. Please don't, to keep all readers of various answers to the challenge "on the same page".)
And there should be another pair of arrays, iXTar[0..n] and iYTar[0..n]
Yes! I just said that the data file that informs the application about the details of the area would not take a brute force approach. And it won't. But inside the application, it will Just Be Easier if the coordinates are available thus.
Different arenas will have different numbers of stations, different numbers of targets.
The index of the last array element needed, this time, for a station reference will go in bStaLastIdx, a byte- type variable. In the example, that would hold 5. (The corresponding variable connected with the targets would be bTarLastIdx, and be 4 for our example arena.
There will also be variables to say where the lines of stations and targets turn: bStaCornIdx, bTarCornIdx. They will hold the indices of the relevant coordinate pairs. In the example they will both hold 2.
By the way... the coordinates of target Z go in iXTar / iYTar, the coordinates of Y go in iXTar and iYTar, and so on.
The data file will be simple plain text, which will be processed one line at a time.
Any line starting with an "/" will be assumed to be a remark, aka "comment", and will be ignored. Lines may also be blank, or consist only of spaces or tab characters. Such lines will also be treated as remarks.
Other lines should all start with an integer* followed by a space. There may be other characters after the space... indeed it will be wise to supply it... but it will be ignored by the application. The data type of the various variables being filled from the data file will inform the range of values that is acceptable. In a perfect world, the app will do range checks. In the meantime, users should be careful. (*"integer": Either just a string of digits, or a string of digits with one and only one "+" or "-" at its start. The integer may have any number of digits, and presence or absence of leading zeros will make no difference.)
What variable a given number is meant to go into will be defined by the position in the file of the non-remark line starting with that number
The first number will be a data format version identifier. (This can be used to check that the datafile matches the "generation" of the application reading it. I.e., if later versions of the application need different data, the data format version ID can be used to see if a given data file is appropriate.) for now, we are setting up "data format version 0001", and there isn't any other at the time of writing.)
Then will come the number of stations. NOT the number which is to go into bStaLastIdx.. the application will convert the "count" figure to a "last index" figure. "Count" is human friendly, and few of the users of the application will have any idea what is going on internally. (Throughout this, we will use "count" numbers where they are visible to humans, and "index" numbers everywhere internally.)
The next number will be the count of targets. Once "1" has been subtracted from it, the result will go into bTarLastIdx.
So far, the data file for the example area could look like the following. Remember that the remark line, and the remarks after the number on the data lines will make no difference to the application.
Any information shown in ( )s in the sample data file will only be there when it is being used by programmers. Ordinary users would have no use for that information.
/A sample data file for the angle calculating program. /edition: 08 Oct 17 /started: 08 Oct 17 /Any line starting "/" is ignored by the application, / as are blank lines. /Other lines must start with "+", "-" or a digit. /Next, more digits. Or not, if the first character / was a digit. /Then, optionally, a space. Anything after the space / is ignored by the application... but good remarks / in your data file will pay dividends. /Note: Only integers are allowed. 3.1415 is not, for instance. 0001 data format version. Must be integer. 6 Count of stations. (bStaLastIdx will be this - 1) 5 Count of targets (bTarLastIdx will be this - 1)
Next, we will tell the application where the line of stations "bends", and then where the line of targets "bends".
In the case of our example, the number in both cases is 3... because the corner is at the third station/ target from where the line starts (A and **Z** respectively.) Again: For the human, we're using a 3... but the application will convert those 3s to 2s, as soon as it fetches them. (The indices of the relevant array elements will be 2, because the elements are "numbered" "from zero"
The values will go into bStaBendAt and bTarBendAt.
So, the data file, so far, for our example arena would look like...
/A sample data file for the angle calculating program. /edition: 08 Oct 17 /started: 08 Oct 17 /Any line starting "/" is ignored by the application, / as are blank lines. /Other lines must start with "+", "-" or a digit. /Next, more digits. Or not, if the first character / was a digit. /Then, optionally, a space. Anything after the space / is ignored by the application... but good remarks / in your data file will pay dividends. /Note: Only integers are allowed. 3.1415 is not, for instance. 0001 data format version. Must be integer. 6 Count of stations. (bStaLastIdx will be: this - 1) 5 Count of targets (bTarLastIdx will be: this - 1) 3 Where line of stations bends. (bStaBend at: this - 1) 3 Where line of targets bends. (bTarBend at: this - 1)
Next we need to tell the application some dimensions which are part of the coordinates of many stations or targets. Names for variables to put these values in are on the diagram above... iXSEW and iYSNW both refer to a dimension of some Station positions, hence the "S" as the second character. The "EW" and "NS" are for "east/ west" and "north/ south", as before.
In a similar vein, there's iXTEW and iYTNS... x and y distances, for Target positions.
The following let's us put numbers on those four dimensions...
The four dimensions would be added to the data file we've already shown the start of, just a moment ago...
2 iXSEW 2 iYSNW 12 iXTEW 8 iYTNS
After that, the rest of the file is quite simple. It could be set up various ways. Let's agree that we will just go through the stations (first) (blue on diagram) and then the targets (green), giving the x or y coordinate for each, which ever one we don't yet know for that particular station or target. Note the fact that this area demonstrates the fact there there's no need to use uniform spacing between stations or targets. Indeed, it may be a bad idea.
Our scale is quite crude here. Note that you can only enter integers into the application. But if you take your measurements in centimeters, in a real-life instance of this exercise, that should pose no problem.
This is the last stuff to be added to the data file we've been building...
/Stations... coord not supplied by common value... 6 A's y coord 5 B's y coord 2 C.. either will do. C only needed as a place holder 4 D's x coord 5 E's x coord /Targets... coord not supplied by common value... 4 Z's y coord 5 Y 12 X.. either will do. C only needed as a place holder 8 W 5 V
... and THAT finishes what needs to go into the data file!
So! Not a trivial exercise... but one that may beneficial exercise your skills in keeping on top of a project.
Please keep to the variable names and types proposed, so that when others read about what you've done, it is easier.
Please keep to the data file format set out above.
Remember that I am interested to see what you can do in respect of achieving the things proposed in this challenge... especially if you use the Lazarus programming language to do it.
Even if you "only" undertake Challenge 1, what you have done will be of interest. Of course, if you manage Challenges 2a or 2b, so much the better.
I hope someone provides a "Challenge 1" answer soon, so that those who don't find that interesting can jump in at Challenge 2a. (And when that's been solved, ditto, to allow people to start with Challenge 2b.)
BEWARE: The search above only visits a selection of my stuff. Go to either of my other sites (see links below) and use that site's FreeFind search button, if you haven't found something you "know is there".
In addition to the tutorials for which this page serves as Table of Contents, I have other sites with material you might find useful.....
My other sites....
Sheepdog Software homepage.
My Arunet homepage.
... and some links to specific pages within them you might want....
You can't "play" all day... learn to use the Libre Office/ Open Office database. Free. Multi-platform.
The Arduino- LOTS of fun, for not much money. And beginner (intelligent beginner) friendly. And good pursuit for kids. Combine programming and electronics!
Designing printed circuit boards the KiCad way. Free. Multi-platform. Long established. PCB-fab houses take native KiCad files.
And lastly... Making maps... how we did it before GPS Indulge me? This discusses a worthwhile, fun (if presented intelligently) activity for kids, which can be undertaken on many levels... a simple 20 minutes, or weeks of engaging activity. (Also known to divert susceptible adults.)
Here is the way to contact the author of these Lazarus/Delphi tutorials, Tom Boyd.
Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. (Mostly passes. A few problems caused by Google+ and Delicious code.)
If this page causes a script to run, why? Because of things like Google panels, and the code for the search button. Why do I mention scripts? Be sure you know all you need to about spyware.
....... P a g e . . . E n d s .....