MathImage Version 3.0 Renate Schaaf 1252N 400E #3 Logan, UT 84321 CompuServe: 71031,2774 Internet: renates@xmission.com schaaf@math.usu.edu TMathImage is a component derived from TImage that I wrote for my own purposes as a basis for interactive math applications. It facilitates the display of mathematical graphs. This is version 3.0 (July 98) which (hopefully) fixes all bugs that have been reported to me and some more which I discovered, and adds more functionality. See 'What's new' below. Source code is included. I'm happy about any feedback, in particular about things that do not quite work. *Platforms: Works both under Delphi 1 and 2 (I have not installed 3 yet -unbelievable-, but people say it works. Got no idea about 4.). *What is does: 2-d-graphing in world-coordinates 3-d-graphing in world-coordinates, with variable world bounds, view distance, view (opening) angle, and view point rotation. This is the cheapest 3-D rendering, there's no 'tilting' the view camera and change of at-point, but its enough for math-graphs. Graphing of wired or filled surfaces, invisible parts hidden. Run the included demo to get an idea. *Usage: You have to register the component before you can use it or any of the demos. Rename the file {$IF using Delphi 1} mathimge.dc1 {$Else} mathimge.dc2 {$ENDIF} to mathimge.dcr. Go to {$IF using Delphi 1} Options.InstallComponent {$Else} Components.Install {$Endif} , select 'Add' and browse to the directory where you have these files. MathImge.pas is the one to install. There are no other units which it uses. It registers to the samples part of the component panel. You can easily change this by changing the procedure register. *Beware*: Under Delphi1, do *not* run the demo with 'Optimize exe-size and load time' checked under the linker part in project options. The demo uses a fake notebook which apparently the Delphi1 optimizer can't handle. It'll freeze on you, otherwise. Besides, I've never seen any noticable result of that option being checked. *Distribution/Pricing: This component is free for noncommercial or educational use. For commercial use, or if you want to use the component as a base for an improved commercial component, contact me. You should not upload this package to other places since I'd like to keep track of where it is. Since the Delphi and Delphi32 forums on Compuserve now really seem to be dying (and I am quite sorry about this), the home of this component is now to be found at http://www.xmission.com/~renates/delphi.html New versions (and other stuff) can be found there, but I'll also upload to the Delphi forum (as long as it's there...). *Disclaimer: ******************************** This software is to be used as is, and I am not responsible for any damage it might cause. ******************************** *Copyright: ********************************************* I retain the copyright for this component. If you use it in an application or as a base for an improved component, you should mention the source. ******************************************** ****Thanks: To everybody at the Delphi-Forum, especially the TeamB members who helped me a lot over the years: Kurt Barthelmess Ralph Friedman Steve Schafer. I also got a very helpful hint in the Borland.. sorry Inprise Newsgroups from Joe Herb Thanks for the program MemProof (free!) to Atanas Stoyanov. *Documentation: The interface of the component 'MathImge.pas' explains the properties and methods. The component is maybe a bit overloaded now, so I should split it into a 2-D and 3-D part, but I'd rather keep as much compatability as possible. You won't catch me writing a help file for this component. MathDemo is a Notebook application that demonstrates some of the component's uses. See filelist below to see what belongs to the demo. Have Fun! Renate Filelist: MathRead.Me (this) MathImge.Pas (MathImage component) MathImge.dc1/dc2(Component resource for Delphi1/2) MathDemo.Dpr (Project file for demo) MathDemo.Res (Resource file for above (it's Delphi1, but is OK for 2)) MDemo1.Pas/Dfm (Units/Formfiles for Demo) Plane.Pas/Dfm ( " } Surface.Pas/Dfm ( " } Ani1.Pas/Dfm ( " } SpCurv.Pas/Dfm ( " } What's new: (Advice: Read backwards) 1.0 to 1.1: 1) Properties are not published any more, you have to set them at run time. This is because I discovered an unexpected behavior with respect to setting defaults of published float properties (with Kurt's help): If you specify a nonzero value as the default, you can never set that property to a value 0 at design time. As a result, in version 1.0, no world bound could be set to 0. On the other hand, setting all world bounds to a default of 0 does not make any sense. So the easy solution was to make them all run time. This way, they are somewhat obsolete, because you can code things shorter using 'setworld' and 'd3setworld'. I've kept them in there to get somewhat of a backwards compatability. 2) The previous version leaked memory, because of a misinformation (I'm convinced, but it's not official) in the manual and on line help. See the 'clear' procedure. The memory it leaks now, it only leaks in the official VCL components and can't lead to anything disturbing. 3) The DrawAxes routine for plane graphs has been much refined. It now sets ticks automatically and puts in number text at intervals. Ticks are always set in distances of powers of 10 and at multiples of that power. I found it working just fine in any circumstances. 4) If the Axes property is set to true, all line drawing is now really clipped to the window within the axes. 5) For 3-D drawing, the picture now always shows the true aspect ratio of the D3-world block. Before, things would get distorted depending on the size of the image. But you have to be careful now when using different orders of magnitude for the range of the 3 variables. 6) The routine to call when the picture gets resized is now 'reset' rather than 'resetworld' or 'd3resetworld'. Reset adjusts the world-to-pixel scales and also resizes the image's bitmap. Versions 1.1-2.0: 1) Fixed a error in the scaling that would show up if you'd set world equal to screen coordinates (miscounted the pixels...). 2) Cleaned up code so it compiles under both Delphi 1 and 2. 3) Prevented the little bitmap to be loaded at design time and into the .exe. Shrinks .exe-size. Don't know why I thought I had to have it in the constructor before... 4) Axes now always (so far) display at the optimal spot. 5) Made the clipping region (hregion) a public variable, so you can refer to it, and also several simultanous instances now don't steal each other's regions. 4) Added routines 'DrawPolyLine' ('DrawPolyPolyLine') which speed up graphing *a lot*. To (at least for my prefences) easily maintain a list of points to be graphed, two new objects 'TFloatPointList' and 'TFloatPointListList' have been introduced. **You need to construct and free these objects as you need them!** (see Demo) 5) Surface drawing has been much facilitated. There is an object 'TSurface' that you have to construct and fill with world-grid-points, then you can pass it to 'D3DrawSurface' (see Demo), free it when not needed anymore. It finally dawned on me how to display filled surfaces right the easy and fast way. (I should have read more, other people have discovered it long before me, of course.) DrawBack, the points on the displayed surface don't know anymore whether they are visible of not. So what. 6) There are lots more pointers in this version. I have not got a Memory Watcher yet for Delphi 2, but I ran the Delphi1-version of the demo through MemMonD. I could not test everything, because its buffer did overflow, but partial testings reveal all (my) pointers freed. Also glad for any 'pointers' on this subject. 2.0 to 2.1: 1) Added DrawPolygon, D3Polyline, D3PolyPolyline. Stupid to not have had them in there before. 2.1 to 3.0: 1) Found a way (thanks, Joe Herb) to publish all the properties defining the D2 and D3 worlds. So they can be set at design time now. 2) Added procedures D3StartRotatingleft, -right, -up, -down etc. and events OnRotating, OnMoving, OnRotateStop, etc. See explanations in the interface part of Mathimge.pas. I found this to decrease the amount of repeated code to write in applications. 3) D3-axes now get some ticks and number labels. I think the D2-axes display a little better now, too. 4) The component now raises an exception EMathImageError whenever the world settings cause an EMathError in the scaling procedures. Whenever the exception is raised while setting new world bounds, the old ones are restored. (See Plane.pas for an example of error handling.) Another exception, ESurfaceError, is raised whenever the construction or drawing of a surface fails. (See Surface.pas for an example for handling this exception.) I hope to have trapped all FInvalidOp, Overflow, ZeroDivide etc. errors this way. But I'm a bit pessimistic. You might still get errors due to the world being too large or too small... I hope all sources for GPF's and AV's are eliminated. I do not want to set minimal or maximal bounds for either the worldsize or the scalings, I'd rather leave that up to you. A thing you should be aware of if you zoom way into a graph: The virtual picture is restricted to a pixel rectangle (-16000,-16000,16000,16000). (This is necessary in Delphi1, because the canvas can really only handle integers, not longint.) Once the to-pixel- scalings of your graph get beyond that, line drawing will be screwed up. 5) You now have the choice of displaying the true aspect ratio of the D3-world or to just see everything scaled to a square box. See property D3AspectRatio. 6) The routine D3SetWorld now *only* has the variables x1,y1,z1,x2,y2,z2. Specify the rest of the world settings using the properties D3Viewdist, D3ViewAngle, D3Yrotation, D3Zrotation, D3Aspectratio. There were so many arguments in D3setworld that I could never memorize their order. I thought you'd have the same problem. 7) The behavior of the image when it is being resized has changed: Except when Autosize is set true, whenever the image bounds change, the bounds of the underlying bitmap change to the same. Flickered drawing is thus avoided. Also, the pixel to world scalings are reset, thus all new drawings are scaled to fit the new image size. An event 'OnResize' fires when this happens, so you can update your previous drawing to the new image size, or just plain erase it. The old routine 'reset' has thus become obsolete, except you have set autosize to true because you want to draw on a loaded bitmap. 8) You can now set pen, brush and font of the drawing as properties of TMathimage instead of of its canvas. They can be set at design time. I redefined the images's canvas property in order to achieve this without a bitmap being stored in form- or exe- files. 9) Thanks to MemProof (Atanas Stoyanov) which came out just in time, I discovered that I had left region-resources dangling around. This is now fixed, and I don't think the component leaks more memory than necessary. (July 1998)