From 22f703cab05b7cd368f4de9e03991b7664dc5022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 1 Sep 2014 13:56:46 +0200 Subject: Initial import of argyll version 1.5.1-8 --- plot/Imakefile | 6 + plot/Jamfile | 27 + plot/License.txt | 662 ++++++++++++++ plot/Makefile.am | 12 + plot/Readme.txt | 2 + plot/afiles | 14 + plot/osx/Jamfile | 21 + plot/osx/Readme.txt | 1 + plot/osx/acoccoa.h | 402 +++++++++ plot/osx/helloc.c | 313 +++++++ plot/osx/hellom.m | 181 ++++ plot/plot.c | 2511 +++++++++++++++++++++++++++++++++++++++++++++++++++ plot/plot.h | 94 ++ plot/vrml.c | 928 +++++++++++++++++++ plot/vrml.h | 113 +++ 15 files changed, 5287 insertions(+) create mode 100644 plot/Imakefile create mode 100644 plot/Jamfile create mode 100644 plot/License.txt create mode 100644 plot/Makefile.am create mode 100644 plot/Readme.txt create mode 100644 plot/afiles create mode 100644 plot/osx/Jamfile create mode 100644 plot/osx/Readme.txt create mode 100644 plot/osx/acoccoa.h create mode 100644 plot/osx/helloc.c create mode 100644 plot/osx/hellom.m create mode 100644 plot/plot.c create mode 100644 plot/plot.h create mode 100644 plot/vrml.c create mode 100644 plot/vrml.h (limited to 'plot') diff --git a/plot/Imakefile b/plot/Imakefile new file mode 100644 index 0000000..316b296 --- /dev/null +++ b/plot/Imakefile @@ -0,0 +1,6 @@ + INCLUDES = -I$(TOP) + DEPLIBS = $(DEPXLIB) +LOCAL_LIBRARIES = $(XLIB) + SYS_LIBRARIES = -lm + +SimpleProgramTarget(plot) diff --git a/plot/Jamfile b/plot/Jamfile new file mode 100644 index 0000000..47bc09e --- /dev/null +++ b/plot/Jamfile @@ -0,0 +1,27 @@ + +# Jamfile for plot library and test program + +#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on +PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags +PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; + +# Compile .c as .m +if $(OS) = MACOSX { + ObjectCcFlags plot : -ObjC ; + ObjectCcFlags plot_plot : -ObjC ; +} + +# PLOT library +Library libplot : plot.c : : : ../h ../numlib ../spectro ; +if $(UNIX) && $(OS) != MACOSX { + ObjectHdrs plot : $(LibWinH) ; +} + +# Individual stand alone test of plot library +MainVariant plot : plot.c : : STANDALONE_TEST : ../h ../numlib ../spectro : : ../spectro/libconv.lib ../numlib/libnum.lib ; + +# VRML plot library +Library libvrml : vrml.c : : : ../h ../icc ../cgats ../numlib ../gamut ; + +#MainsFromSources t.c ; + diff --git a/plot/License.txt b/plot/License.txt new file mode 100644 index 0000000..a871fcf --- /dev/null +++ b/plot/License.txt @@ -0,0 +1,662 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. + diff --git a/plot/Makefile.am b/plot/Makefile.am new file mode 100644 index 0000000..eabcb91 --- /dev/null +++ b/plot/Makefile.am @@ -0,0 +1,12 @@ +include $(top_srcdir)/Makefile.shared + +privatelib_LTLIBRARIES = libplot.la libvrml.la +privatelibdir = $(pkglibdir) + +libplot_la_SOURCES = plot.h plot.c +libplot_la_LIBADD = $(X_LIBS) + +libvrml_la_SOURCES = vrml.h vrml.c +libvrml_la_LIBADD = $(ICC_LIBS) ../numlib/libargyllnum.la + +EXTRA_DIST = License.txt Readme.txt diff --git a/plot/Readme.txt b/plot/Readme.txt new file mode 100644 index 0000000..df5a0c0 --- /dev/null +++ b/plot/Readme.txt @@ -0,0 +1,2 @@ +A simple Windows NT/X11 2d graph plot library, +to quickly display graphs and points for debug purposes. diff --git a/plot/afiles b/plot/afiles new file mode 100644 index 0000000..0fbf8c6 --- /dev/null +++ b/plot/afiles @@ -0,0 +1,14 @@ +Readme.txt +License.txt +Jamfile +Imakefile +afiles +plot.c +plot.h +vrml.c +vrml.h +osx/Readme.txt +osx/Jamfile +osx/helloc.c +osx/acoccoa.h +osx/hellom.m diff --git a/plot/osx/Jamfile b/plot/osx/Jamfile new file mode 100644 index 0000000..933d56d --- /dev/null +++ b/plot/osx/Jamfile @@ -0,0 +1,21 @@ + +# Jamfile for OS X window code development + +#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on +PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags +#PREF_CCFLAGS += -x objective-c ; +PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; + +# Hello world +#Main hello : hello.m ; + +# Hello world window in C +Main helloc : helloc.c ; + +# Hello world window in Objective-C +ObjectCcFlags hellom : -ObjC ; +Main hellom : hellom.m ; + +#GuiBin tt ; +#Main tt : tt.m ; + diff --git a/plot/osx/Readme.txt b/plot/osx/Readme.txt new file mode 100644 index 0000000..44b083b --- /dev/null +++ b/plot/osx/Readme.txt @@ -0,0 +1 @@ +Develop Cocoa based simple window code. diff --git a/plot/osx/acoccoa.h b/plot/osx/acoccoa.h new file mode 100644 index 0000000..ba88cd4 --- /dev/null +++ b/plot/osx/acoccoa.h @@ -0,0 +1,402 @@ + +#ifndef ACOCCOA_H + +/* OS X Coccoa support code for Argyll. */ +/* In some places we really prefer not to have OS X code */ +/* in separate .m files, so we'll do it all from C. */ + +#include + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 +# include +# include +#else +# include + +/* Objective-C runtime compatibility functions for < 10.5 */ + +/* Create a class definition, but don't register it */ +Class CreateClassDefinition(const char *name, const char *superclassName) { + struct objc_class *meta_class; + struct objc_class *super_class; + struct objc_class *new_class; + struct objc_class *root_class; + + // Ensure that the superclass exists and that someone + // hasn't already implemented a class with the same name + // + super_class = (struct objc_class *)objc_lookUpClass(superclassName); + if (super_class == nil) { + printf("failed to lookup '%s'\n",superclassName); + return Nil; + } + + if (objc_lookUpClass(name) != nil) { + return Nil; + } + + // Find the root class + root_class = super_class; + while(root_class->super_class != nil) + root_class = root_class->super_class; + + // Allocate space for the class and its metaclass + if ((new_class = calloc(2, sizeof(struct objc_class))) == NULL) { + return Nil; + } + meta_class = &new_class[1]; + + // setup class + new_class->isa = meta_class; + new_class->info = CLS_CLASS; + meta_class->info = CLS_META; + + // Create a copy of the class name. + // For efficiency, we have the metaclass and the class itself + // to share this copy of the name, but this is not a requirement + // imposed by the runtime. + if ((new_class->name = strdup(name)) == NULL) { + free(new_class); + } + meta_class->name = new_class->name; + + // Allocate empty method lists. + // We can add methods later. + if ((new_class->methodLists = calloc( 1, sizeof(struct objc_method_list *))) == NULL) { + free((void *)new_class->name); + free(new_class); + return Nil; + } + *new_class->methodLists = (struct objc_method_list *) -1; + if ((meta_class->methodLists = calloc(1, sizeof(struct objc_method_list *))) == NULL) { + free(new_class->methodLists); + free((void *)new_class->name); + free(new_class); + return Nil; + } + *meta_class->methodLists = (struct objc_method_list *) -1; + + // Connect the class definition to the class hierarchy: + // Connect the class to the superclass. + // Connect the metaclass to the metaclass of the superclass. + // Connect the metaclass of the metaclass to the metaclass of the root class. + new_class->super_class = super_class; + meta_class->super_class = super_class->isa; + meta_class->isa = (void *)root_class->isa; + + // Set the sizes of the class and the metaclass. + new_class->instance_size = super_class->instance_size; + meta_class->instance_size = meta_class->super_class->instance_size; + + return new_class; +} + +/* Add an array of methods. Null terminated by name array */ +/* We assume that the class is being created, and that there are */ +/* no existing methods. */ +BOOL registerDynamicMethods(Class cls, const char *mnames[], IMP mimps[], const char *mtypes[]) { + int i, nmeth; + struct objc_method_list *methodList; + + /* Count the number of methods */ + for (nmeth = 0; mnames[nmeth] != NULL && mnames[nmeth][0] != '\000'; nmeth++) + ; + + /* Allocate an array */ + methodList = malloc(sizeof(struct objc_method_list) + (nmeth-1) * sizeof(struct objc_method)); + + methodList->method_count = nmeth; + for (i = 0; i < nmeth; i++) { + // Get or register the selector for the method name + SEL methodSEL = SELUID(mnames[i]); + + // Registering the method seems to register the selector + if (ISSELECTOR(methodSEL) == NO) { + methodSEL = sel_registerName(mnames[i]); + } + + // Fill out the method list + methodList->method_list[i].method_name = methodSEL; + methodList->method_list[i].method_imp = mimps[i]; + methodList->method_list[i].method_types = strdup(mtypes[i]); + } + + // Register our methods + class_addMethods((Class)cls, methodList); + + return YES; +} + +/* Add an array of instance variables. Null terminated by name array */ +/* We assume that the class is being created, and that there are */ +/* no existing methods. */ +BOOL registerDynamicVariables(Class cls, const char *names[], size_t sizes[], const char *types[]) { + int i, nvar = 1; + int vsize; + struct objc_ivar *ivarp; + + /* Count the number of variables */ + for (nvar = 0; names[nvar] != NULL && names[nvar][0] != '\000'; nvar++) + ; + + vsize = sizeof(struct objc_ivar_list) + (nvar - 1) * sizeof(struct objc_ivar); + cls->ivars = calloc(vsize, 1); + cls->ivars->ivar_count = nvar; + + for (i = 0; i < nvar; i++) { + int abytes; + ivarp = &cls->ivars->ivar_list[i]; + + /* Set the variable information */ + ivarp->ivar_name = strdup(names[i]); + ivarp->ivar_type = strdup(types[i]); + + /* Align the offset for this variable to it's size, limiting to 64 bits */ + if ((abytes = sizes[i]) > 8) + abytes = 8; + cls->instance_size = (cls->instance_size + abytes-1) & ~(abytes-1); + ivarp->ivar_offset = (int)cls->instance_size; + cls->instance_size += sizes[i]; + } + + return YES; +} + +#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 */ + +extern id NSApp; + +/* Create a class */ +BOOL registerClass( +const char *name, /* Name of class being created */ +const char *supername, /* Name of superclass */ +const char *methnames[], /* List of method names, empty string terminated */ +IMP methimps[], /* Method implementations */ +const char *methsigs[], /* Method signatures */ +const char *varnames[], /* List of variable names, empty string terminated */ +size_t varsizes[], /* Variable size in bytes */ +const char *varsigs[] /* Variable signatures */ +) { + int i; + Class nclass; + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 + nclass = objc_allocateClassPair((Class)objc_getClass(supername), name, 0); + if (nclass == Nil) { + return NO; + } + + for (i = 0; methnames[i] != NULL && methnames[i][0] != '\000'; i++) { + class_addMethod(nclass, sel_getUid(methnames[i]), methimps[i], methsigs[i]); + } + + // Should check return value is YES + for (i = 0; varnames[i] != NULL && varnames[i][0] != '\000'; i++) { + int asize; + while( (1 << asize) < varsizes[i] && asize < 8) + asize++; + class_addIvar(nclass, varnames[i], varsizes[i], asize, varsigs[i]); + } + + // Must be called after adding instance variable + objc_registerClassPair(nclass); +#else + /* Use compat.h functions to do the dirty work */ + // Should check the return value! + if ((nclass = CreateClassDefinition(name, supername)) == Nil) { + return NO; + } + + registerDynamicMethods(nclass, methnames, methimps, methsigs); + + registerDynamicVariables(nclass, varnames, varsizes, varsigs); + + // Register the class with the runtime. + objc_addClass(nclass); +#endif + return YES; +} + +/* ------------------------------------------------ */ +/* One of the primary disadvantages of coding Coccoa in C */ +/* is the lack of compatible .h files. We have to make our own.. */ + +/* ------------------------------------------------ */ + +/* Foundation stuff */ + +#ifndef __OBJC__ + +#if !defined(FSTATIC_INLINE) +# if defined (__GNUC__) && (__GNUC__ == 4) +# define FSTATIC_INLINE static __inline__ __attribute__((always_inline)) +# else +# define FSTATIC_INLINE static __inline__ +# endif +#endif + +#ifdef __LP64__ +typedef double NSFloat; +#else +typedef float NSFloat; +#endif + +typedef struct _NSPoint { + NSFloat x; + NSFloat y; +} NSPoint; + +FSTATIC_INLINE NSPoint NSMakePoint(NSFloat x, NSFloat y) { + NSPoint r; + r.x = x; + r.y = y; + return r; +} + +typedef struct _NSSize { + NSFloat width; + NSFloat height; +} NSSize; + +FSTATIC_INLINE NSSize NSMakeSize(NSFloat w, NSFloat h) { + NSSize r; + r.width = w; + r.height = h; + return r; +} + + +typedef struct _NSRect { + NSPoint origin; + NSSize size; +} NSRect; + +FSTATIC_INLINE NSRect NSMakeRect(NSFloat x, NSFloat y, NSFloat w, NSFloat h) { + NSRect r; + r.origin.x = x; + r.origin.y = y; + r.size.width = w; + r.size.height = h; + return r; +} + +#endif /* !__OBJC__ */ + +/* ------------------------------------------------ */ +/* Constats for NSString class */ + +/* 10.4 and latter */ +typedef enum { + NSStringDrawingUsesLineFragmentOrigin = (1 << 0), + NSStringDrawingUsesFontLeading = (1 << 1), + NSStringDrawingDisableScreenFontSubstitution = (1 << 2), + NSStringDrawingUsesDeviceMetrics = (1 << 3), + NSStringDrawingOneShot = (1 << 4), + NSStringDrawingTruncatesLastVisibleLine = (1 << 5) +} NSStringDrawingOptions; + +/* ------------------------------------------------ */ +/* Constats for NSApplication class */ + +typedef enum { + NSApplicationPresentationDefault = 0, + NSApplicationPresentationAutoHideDock = (1 << 0), + NSApplicationPresentationHideDock = (1 << 1), + NSApplicationPresentationAutoHideMenuBar = (1 << 2), + NSApplicationPresentationHideMenuBar = (1 << 3), + NSApplicationPresentationDisableAppleMenu = (1 << 4), + NSApplicationPresentationDisableProcessSwitching = (1 << 5), + NSApplicationPresentationDisableForceQuit = (1 << 6), + NSApplicationPresentationDisableSessionTermination = (1 << 7), + NSApplicationPresentationDisableHideApplication = (1 << 8), + NSApplicationPresentationDisableMenuBarTransparency = (1 << 9), + NSApplicationPresentationFullScreen = (1 << 10), + NSApplicationPresentationAutoHideToolbar = (1 << 11) +} NSApplicationPresentationOptions; + +typedef enum { + NSTerminateCancel = 0, + NSTerminateNow = 1, + NSTerminateLater = 2 +} NSApplicationTerminateReply; + +/* ------------------------------------------------ */ +/* Constats for NSWindow class */ + +enum { + NSBorderlessWindowMask = 0, + NSTitledWindowMask = 1 << 0, + NSClosableWindowMask = 1 << 1, + NSMiniaturizableWindowMask = 1 << 2, + NSResizableWindowMask = 1 << 3, + NSTexturedBackgroundWindowMask = 1 << 8 +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 + ,NSUnscaledWindowMask = 1 << 11, + NSUnifiedTitleAndToolbarWindowMask = 1 << 12 +#endif +}; + +/* types of window backing store */ +typedef enum { + NSBackingStoreRetained = 0, + NSBackingStoreNonretained = 1, + NSBackingStoreBuffered = 2 +} NSBackingStoreType; + + +/* ------------------------------------------------ */ +/* Convenience functions */ + +/* Transform process to interact with descktop */ +void transProcess() { + OSStatus stat; + ProcessSerialNumber psn = { 0, 0 }; + + if (GetCurrentProcess(&psn) != noErr) { + /* Transform the process so that the desktop interacts with it properly. */ + /* We don't need resources or a bundle if we do this. */ + if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn, + kProcessTransformToForegroundApplication)) != noErr) + fprintf(stderr,"TransformProcess failed with code %d\n",stat); + } +} + +/* Send a message to the object */ +#define sendMsg(oid, msg, ...) objc_msgSend(oid, sel_getUid(msg), ##__VA_ARGS__) + +/* alloc and init a new object */ +id newObject(const char *cname) { + id rv; + rv = objc_msgSend(objc_getClass(cname), sel_getUid("alloc")); + rv = objc_msgSend(rv, sel_getUid("init")); + return rv; +} +/* release an object */ +void delObject(id oid) { + objc_msgSend(oid, sel_getUid("release")); +} + +/* dealloc super */ +void delObjectSuper(id oid) { + struct objc_super ss; + ss.receiver = oid; +#ifdef __OBJC__ + ss.super_class = sendMsg(oid, "superclass"); +#else + ss.class = (Class)sendMsg(oid, "superclass"); +#endif + objc_msgSendSuper(&ss, sel_getUid("dealloc")); +} + +/* Create an NSString from a C string */ +id newNSString(const char *cstr) { + id str; + + str = objc_msgSend(objc_getClass("NSString"), sel_getUid("alloc")); + str = objc_msgSend(str, sel_getUid("initWithUTF8String:"), cstr); + + return str; +} + +#define ACOCCOA_H +#endif /* ACOCCOA_H */ diff --git a/plot/osx/helloc.c b/plot/osx/helloc.c new file mode 100644 index 0000000..9150989 --- /dev/null +++ b/plot/osx/helloc.c @@ -0,0 +1,313 @@ + +#include +#include +#include + +#ifdef __OBJC__ +# include +# include +#endif + +#include "acocoa.h" /* Argyll Cocoa support functions and defines */ + +/* +- (void) someMethod:... +{ + va_list va; + + va_start(va, _cmd); + + // process all args with va_arg + + va_end(va); +} + */ + +/* Our static instance variables for AppDelegate */ +typedef struct { + id window; /* NSWindow */ + id view; /* NSView */ +} cntx_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +void MyView_setCntx(id self, SEL _cmd, void *val) { + object_setInstanceVariable(self, "cntx", val); +} + +void MyView_drawRect(id self, SEL _cmd, NSRect rect) { + double w = rect.size.width, h = rect.size.height; + + id aPath = sendClassMsg("NSBezierPath", "bezierPath"); + sendMsg(aPath, "setLineWidth:", 2.0); + sendMsg(aPath, "moveToPoint:", NSMakePoint(0.0, 0.0)); + sendMsg(aPath, "lineToPoint:", NSMakePoint(0.9 * w, 0.9 * h)); + sendMsg(aPath, "appendBezierPathWithRect:", NSMakeRect(0.5 * w, 0.5 * h, + 0.7 * w, 0.6 * h)); + sendMsg(aPath, "stroke"); + + { + id att = newObject("NSDictionary"); + id str = newNSString("String"); + sendMsg(str, "drawAtPoint:withAttributes:", NSMakePoint(0.1 * w, 0.1 * h), att); + } +} + +/* Clean up */ +void MyView_dealloc(id self, SEL _cmd) { + delObjectSuper(self); +} + +// Create our custom NSView */ +void createMyView() { + method_info minfo[] = { + { "setCntx:", (IMP)MyView_setCntx, "v@:^v" }, + { "drawRect:", (IMP)MyView_drawRect, "v@:@" }, + { "dealloc", (IMP)MyView_dealloc, "v@:" }, + { "" } + }; + + variable_info vinfo[] = { + { "cntx", sizeof(void *), "^v" }, + { "" } + }; + + registerClass("MyView", "NSView", minfo, vinfo); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +void MyWin_setCntx(id self, SEL _cmd, void *val) { + object_setInstanceVariable(self, "cntx", val); +} + +void MyWin_keyDown(id self, SEL _cmd, id event) { + int etype; + id nresp; + id str; + const char *cstr; + + etype = (int)sendMsg(event, "type"); + str = sendMsg(event, "characters"); + cstr = cNSString(str); + printf("Got Window KeyDown type %d, chars '%s'\n",etype, cstr); + + if (cstr[0] == ' ') + sendMsg(NSApp, "terminate:", self); +} + +/* Clean up */ +void MyWin_dealloc(id self, SEL _cmd) { + delObjectSuper(self); +} + +// Create our custom NSWin */ +void createMyWin() { + method_info minfo[] = { + { "setCntx:", (IMP)MyWin_setCntx, "v@:^v", }, + { "keyDown:", (IMP)MyWin_keyDown, "v@:@", }, + { "dealloc", (IMP)MyWin_dealloc, "v@:" }, + { "" } + }; + + variable_info vinfo[] = { + { "cntx", sizeof(void *), "^v" }, + { "" } + }; + + registerClass("MyWin", "NSWindow", minfo, vinfo); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* Create all the bits */ +void AppDel_willFinishLaunching(id self, SEL _cmd, id notification) { + cntx_t *cx; + id label; /* NSTextField */ + + cx = calloc(1, sizeof(cntx_t)); + + // Set cntx to to allocated structure + object_setInstanceVariable(self, "cntx", (void *)cx); + + /* Create Window */ + cx->window = sendClassMsg("MyWin", "alloc"); + cx->window = sendMsg(cx->window, + "initWithContentRect:styleMask:backing:defer:", + NSMakeRect(300, 300, 200, 100), + NSTitledWindowMask + | NSClosableWindowMask + | NSMiniaturizableWindowMask + | NSResizableWindowMask, + NSBackingStoreBuffered, + YES); + + /* Make the background white */ + sendMsg(cx->window, "setBackgroundColor:", sendClassMsg("NSColor","whiteColor")); + + /* Add title */ + sendMsg(cx->window, "setTitle:", newNSString("Hello World")); + +#ifdef NEVER + /* Create Label */ + label = sendClassMsg("NSTextField", "alloc"); + label = sendMsg(label, "initWithFrame:", NSMakeRect(30, 30, 80, 30)); + + sendMsg(label, "setSelectable:", NO); + sendMsg(label, "setBezeled:", NO); + sendMsg(label, "setDrawsBackground:", NO); + sendMsg(label, "setStringValue:", newNSString("Hello World")); + + /* Hmm. How does this work ? */ + cx->view = sendMsg(cx->window, "contentView"); + sendMsg(cx->view, "addSubview:", label); +#else + /* Use our custom view to draw contents */ + cx->view = newObject("MyView"); + + sendMsg(cx->view, "setCntx:", (void *)cx); + sendMsg(cx->window, "setContentView:", cx->view); + +// sendMsg(cx->window, "setInitialFirstResponder:", cx->view); +#endif + + // Window methods: + + // sendEvent: gets messages. + + // Set above the screen saver + // [aWindow setLevel:NSScreenSaverWindowLevel + 1]; + + // setCollectionBehavior: NSWindowCollectionBehaviorIgnoresCycle + // NSWindowCollectionBehaviorFullScreenPrimary + // NSWindowCollectionBehaviorStationary + // NSWindowCollectionBehaviorIgnoresCycle + + // center + // mouseDownCanMoveWindow + // setMovable: + // setContentMinSize: and setContentMaxSize: + // + // NSRect frame = [myWindow frame]; + // if (frame.size.width <= MIN_WIDTH_WITH_ADDITIONS) + // frame.size.width = MIN_WIDTH_WITH_ADDITIONS; + // frame.size.height += ADDITIONS_HEIGHT; + // frame.origin.y -= ADDITIONS_HEIGHT; + // [myWindow setFrame:frame display:YES animate:YES]; + // objc_msgSend(label, "release")); + // + // setExcludedFromWindowsMenu:YES + // + // setBackgroundColor: and setAlphaValue: + + // WindowImage object: + // setDepthLimit: + + // Setting cursor: + // NSTrackingArea class, along with the cursorUpdate: method of the NSResponder class + +} + +/* Map the window */ +void AppDel_didFinishLaunching(id self, SEL _cmd, id notification) { + cntx_t *cx; + + object_getInstanceVariable(self, "cntx", (void **)&cx); + sendMsg(cx->window, "makeKeyAndOrderFront:", self); + +#ifdef NEVER /* Test terminate */ + sleep(5); + sendMsg(NSApp, "terminate:", self); +#endif +} + +/* Should the application terminate ? */ +NSApplicationTerminateReply AppDel_shouldTerminate(id self, SEL _cmd, id notification) { + return NSTerminateNow; +} + +/* Clean up */ +void AppDel_dealloc(id self, SEL _cmd) { + cntx_t *cx; + + object_getInstanceVariable(self, "cntx", (void **)&cx); + delObject(cx->window); + delObjectSuper(self); +} + +// Create the delegate class that implements our window +void createAppDelClass() { + method_info minfo[] = { + { "applicationWillFinishLaunching:", (IMP)AppDel_willFinishLaunching, "v@:@" }, + { "applicationDidFinishLaunching:", (IMP)AppDel_didFinishLaunching, "v@:@" }, + { "applicationShouldTerminate:", (IMP)AppDel_shouldTerminate, "i@:@" }, + { "dealloc", (IMP)AppDel_dealloc, "v@:" }, + { "" } + }; + + variable_info vinfo[] = { + { "cntx", sizeof(void *), "^v" }, + { "" } + }; + + registerClass("AppDelegate", "NSObject", minfo, vinfo); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - */ +int main(int argc, char** argv) { + id pool; + id appDelObj; + + /* Transform process so that it interacts with desktop properly */ + transProcess(); + + /* Create an autorelease pool */ + pool = newObject("NSAutoreleasePool"); + + // Create all the classes we override + createAppDelClass(); + createMyWin(); + createMyView(); + + // Get our shared NSApplication and start it + sendClassMsg("NSApplication", "sharedApplication"); + + if (NSApp == NULL) { + fprintf(stderr,"Failed to initialized NSApplication... terminating...\n"); + return -1; + } + + /* Set a delegate to create the window */ + appDelObj = newObject("AppDelegate"); + sendMsg(NSApp, "setDelegate:", appDelObj); + +// if running on 10.7: +// sendMsg(NSApp, "disableRelaunchOnLogin")); + + /* Call the run loop */ + sendMsg(NSApp, "run"); + + // detachDrawingThread:toTarget:withObject: + + /* To terminate: + sendMsg(NSApp, "terminate:", self); + */ + + /* We're done with the pool */ + delObject(pool); + + return EXIT_SUCCESS; +} + +#ifdef NEVER + +- (void)drawRect:(NSRect)rect +{ + NSRect r = NSMakeRect(10, 10, 50, 60); + NSBezierPath *bp = [NSBezierPath bezierPathWithRect:r]; + NSColor *color = [NSColor blueColor]; + [color set]; + [bp fill]; +} + +#endif diff --git a/plot/osx/hellom.m b/plot/osx/hellom.m new file mode 100644 index 0000000..b306878 --- /dev/null +++ b/plot/osx/hellom.m @@ -0,0 +1,181 @@ + +#include +#include + +#include /* For diagnostics */ + +typedef struct { + id window; /* NSWindow */ + id view; /* NSTextField */ +} cntx_t; + +// - - - - - - - - - - - - - - - - - - - - - - - - - +@interface MyView : NSView { + void *cntx; +} +- (void)setCntx:(void *)cntx; +@end + +@implementation MyView + +- (void)setCntx:(void *)val { + cntx = val; +} + +- (void)drawRect:(NSRect)rect { +// NSGraphicsContext* aContext = [NSGraphicsContext currentContext]; + + [[NSColor redColor] setStroke]; + + NSBezierPath* aPath = [NSBezierPath bezierPath]; + [aPath setLineWidth:2.0]; + [aPath moveToPoint:NSMakePoint(0.0, 0.0)]; + [aPath lineToPoint:NSMakePoint(100.0, 100.0)]; + [aPath appendBezierPathWithRect:NSMakeRect(20.0, 160.0, 80.0, 50.0)]; + + [aPath stroke]; + + NSDictionary *att = [NSDictionary new]; + + [ @"String" drawAtPoint: NSMakePoint(10.0, 10.0) withAttributes: att ]; + +/* + +[@"Hello" drawInRect:r withAttributes:[NSDictionary +dictionaryWithObjectsAndKeys: +[NSColor redColor], NSForegroundColorAttributeName, +[NSFont systemFontOfSize:24], NSFontAttributeName, +nil]]; + +*/ +} + +@end + +/* To trigger an update: + +Send a setNeedsDisplayInRect: or setNeedsDisplay: message to the +view. Sending either of these messages marks part or all of the view as invalid + + */ + +// - - - - - - - - - - - - - - - - - - - - - - - - - + +@interface MyWin : NSWindow { + void *cntx; +} +- (void)setCntx:(void *)cntx; +@end + +@implementation MyWin + +- (void)setCntx:(void *)val { + cntx = val; +} + +- (void)keyDown:(NSEvent *)event { + printf("Got Window KeyDown type %d char %s\n",[event type], + [[event characters] cStringUsingEncoding:NSASCIIStringEncoding]); +} + +- (BOOL)windowShouldClose:(id)sender { + printf("Got Window windowShouldClose\n"); + [NSApp terminate: nil]; + return YES; +} + +@end + +// - - - - - - - - - - - - - - - - - - - - - - - - - + +@interface AppDelegate : NSObject { + void *cntx; +} +@end + +@implementation AppDelegate +- (void) applicationWillFinishLaunching: (NSNotification *)not { + cntx_t *cx; + + cx = calloc(1, sizeof(cntx_t)); + + cntx = (void *)cx; + + /* Create Window */ + cx->window = [[MyWin alloc] initWithContentRect: NSMakeRect(300, 300, 200, 100) + styleMask: (NSTitledWindowMask | + NSClosableWindowMask | + NSMiniaturizableWindowMask | + NSResizableWindowMask) + backing: NSBackingStoreBuffered + defer: YES]; + [cx->window setTitle: @"Hello World"]; + +#ifdef NEVER + /* Create Label */ + cx->label = [[NSTextField alloc] initWithFrame: NSMakeRect(30, 30, 80, 30)]; + [cx->label setSelectable: NO]; + [cx->label setBezeled: NO]; + [cx->label setDrawsBackground: NO]; + [cx->label setStringValue: @"Hello World"]; + + [[cx->window contentView] addSubview: cx->label]; + + [cx->label release]; + +#else + cx->view = [MyView new]; + [cx->view setCntx:(void *)cx]; + [cx->window setContentView: cx->view]; +#endif + // [window setContentView:customView] +} + +- (void) applicationDidFinishLaunching: (NSNotification *) not { + cntx_t *cx = (cntx_t *)cntx; + [cx->window makeKeyAndOrderFront: self]; +} + +- (void) dealloc { + cntx_t *cx = (cntx_t *)cntx; + [cx->window release]; + [super dealloc]; +} +@end + +// - - - - - - - - - - - - - - - - - - - - - - - - - + +int main (int argc, const char **argv) +{ + NSAutoreleasePool *pool; + id appDelObj; + + if (NSApp == nil) { + OSStatus stat; + ProcessSerialNumber psn = { 0, 0 }; + + if (GetCurrentProcess(&psn) == noErr) { + /* Transform the process so that the desktop interacts with it properly. */ + /* We don't need resources or a bundle if we do this. */ + if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn, + kProcessTransformToForegroundApplication)) != noErr) + fprintf(stderr,"TransformProcess failed with code %d\n",stat); + } + + pool = [NSAutoreleasePool new]; + + [NSApplication sharedApplication]; + appDelObj = [AppDelegate new]; + [NSApp setDelegate: appDelObj]; + + // Run the event loop until done + [NSApp run]; + + [pool release]; + } + + // To terminate: + // [NSApp terminate: nil]; +} + + diff --git a/plot/plot.c b/plot/plot.c new file mode 100644 index 0000000..c5ca910 --- /dev/null +++ b/plot/plot.c @@ -0,0 +1,2511 @@ + +/* + * Copyright 1998 - 2004 Graeme W. Gill + * All rights reserved. + * + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License.txt file for licencing details. + */ + +/* This is a simple 2d graph plotter that runs on MSWindows/OSX/X11 */ +/* The code is in three sections, one for each GUI environment. */ +/* (Perhaps common code could be consolidated ?) */ + + +/* + * TTBD: + * + * Allow for a window title for each plot. + * + * Put all state information in plot_info (window handles etc.) + * Create thread to handle events, so it updates correctly. + * (Will have to lock plot info updates or ping pong them); + * Have call to destroy window. + * (Could then move to having multiple instances of plot). + * + * OS X Cocoa code doesn't get window focus. No idea why. + * + */ + +#include +#include +#include +#include +#ifdef UNIX +#include +#endif +#include +#include "numlib.h" +#include "plot.h" + +#undef DODEBUG /* Print error messages & progress reports */ +//#define STANDALONE_TEST /* Defined by build script */ + +#define NTICK 10 +#define LTHICK 1.2 /* Plot line thickness */ +#define ILTHICK ((int)(LTHICK+0.5)) /* Integer line thickness */ +//#define ILTHICK 2 +#undef CROSSES /* Mark input points with crosses */ + +#define DEFWWIDTH 500 +#define DEFWHEIGHT 500 + +/* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */ +/* Brown = Y7, Orange = Y8, Grey = Y9, Magenta = Y10 */ + +double nicenum(double x, int round); + +#define MXGPHS 10 /* Number of graphs with common X axis */ + +/* Colors of the graphs */ +static int gcolors[MXGPHS][3] = { + { 0, 0, 0}, /* Black */ + { 210, 30, 0}, /* Red */ + { 0, 200, 90}, /* Green */ + { 0, 10, 255}, /* Blue */ + { 200, 200, 0}, /* Yellow */ + { 220, 0, 255}, /* Purple */ + { 136, 86, 68}, /* Brown */ + { 248, 95, 0}, /* Orange */ + { 160, 160, 160}, /* Grey */ + { 220, 30, 220} /* Magenta */ +}; + +/* Information defining plot */ +/* There is one global instance of this. */ +struct _plot_info { + void *cx; /* Other Context */ + + int dowait; /* Wait for user key if > 0, wait for n secs if < 0 */ + double ratio; /* Aspect ratio of window, X/Y */ + + /* Plot point information */ + double mnx, mxx, mny, mxy; /* Extrema of values to be plotted */ + int graph; /* NZ if graph, Z if vectors */ + int revx; /* reversed X axis */ + + double *x1, *x2; + double *yy[MXGPHS]; /* y1 - y10 */ + char **ntext; + int n; + + double *x7, *y7; + plot_col *mcols; + char **mtext; + int m; + + double *x8, *y8, *x9, *y9; + plot_col *ocols; + int o; + + /* Plot instance information */ + int sx,sy; /* Screen offset */ + int sw,sh; /* Screen width and height */ + double scx, scy; /* Scale from input values to screen pixels */ + + }; typedef struct _plot_info plot_info; + +/* Global to transfer info to window callback */ +static plot_info pd; + +/* Declaration of superset */ +static int do_plot_imp( + double xmin, double xmax, double ymin, double ymax, /* Bounding box */ + double ratio, /* Aspect ratio of window, X/Y */ + int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */ + double *x1, double *x2, + double *yy[MXGPHS], char **ntext, + int n, + double *x7, double *y7, plot_col *mcols, char **mtext, + int m, + double *x8, double *y8, double *x9, double*y9, plot_col *ocols, + int o +); + + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* Public routines */ +/* Plot up to 3 graphs. Wait for key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot( +double *x, +double *y1, /* Up to 3 graphs */ +double *y2, +double *y3, +int n) { + int i, j; + double xmin, xmax, ymin, ymax; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + NULL, NULL, NULL, NULL, 0, + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 3 graphs + crosses. Wait for key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot_p( +double *x, +double *y1, /* Up to 3 graphs */ +double *y2, +double *y3, +int n, +double *x4, double *y4, /* And crosses */ +int m) { + int i, j; + double xmin, xmax, ymin, ymax; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + for (i = 0; i < m; i++) { + if (x4 != NULL) { + if (xmin > x4[i]) + xmin = x4[i]; + if (xmax < x4[i]) + xmax = x4[i]; + } + if (y4 != NULL) { + if (ymin > y4[i]) + ymin = y4[i]; + if (ymax < y4[i]) + ymax = y4[i]; + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + x4, y4, NULL, NULL, m , + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Plot up to 3 graphs with specified window size. */ +/* if dowait > 0, wait for user key */ +/* if dowait < 0, wait for no seconds */ +/* If xmax > xmin, use as x scale, else auto. */ +/* If ymax > ymin, use as y scale, else auto. */ +/* ratio is window X / Y */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot_x( +double *x, +double *y1, +double *y2, +double *y3, +int n, +int dowait, +double pxmin, +double pxmax, +double pymin, +double pymax, +double ratio +) { + int i, j; + double xmin, xmax, ymin, ymax; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + if (pxmax > pxmin) { + xmax = pxmax; + xmin = pxmin; + } + if (pymax > pymin) { + ymax = pymax; + ymin = pymin; + } + + return do_plot_imp(xmin, xmax, ymin, ymax, ratio, dowait, + x, NULL, yy, NULL, n, + NULL, NULL, NULL, NULL, 0, + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 6 graphs. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot6( +double *x, /* X coord */ +double *y1, /* Black */ +double *y2, /* Red */ +double *y3, /* Green */ +double *y4, /* Blue */ +double *y5, /* Yellow */ +double *y6, /* Purple */ +int n) { /* Number of values */ + int i, j; + double xmin, xmax, ymin, ymax; + int nn = abs(n); + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + yy[3] = y4; + yy[4] = y5; + yy[5] = y6; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + NULL, NULL, NULL, NULL, n , + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 6 graphs + optional crosses. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot6p( +double *x, /* X coord */ +double *y1, /* Black */ +double *y2, /* Red */ +double *y3, /* Green */ +double *y4, /* Blue */ +double *y5, /* Yellow */ +double *y6, /* Purple */ +int n, /* Number of values */ +double *xp, double *yp, /* And crosses */ +int m) { + int i, j; + double xmin, xmax, ymin, ymax; + int nn = abs(n); + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + yy[3] = y4; + yy[4] = y5; + yy[5] = y6; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + for (i = 0; i < m; i++) { + if (xp != NULL) { + if (xmin > xp[i]) + xmin = xp[i]; + if (xmax < xp[i]) + xmax = xp[i]; + } + if (yp != NULL) { + if (ymin > yp[i]) + ymin = yp[i]; + if (ymax < yp[i]) + ymax = yp[i]; + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + xp, yp, NULL, NULL, m, + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 10 graphs. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot10( +double *x, /* X coord */ +double *y1, /* Black */ +double *y2, /* Red */ +double *y3, /* Green */ +double *y4, /* Blue */ +double *y5, /* Yellow */ +double *y6, /* Purple */ +double *y7, /* Brown */ +double *y8, /* Orange */ +double *y9, /* Grey */ +double *y10,/* White */ +int n, /* Number of values */ +int zero /* Flag - make sure zero is in y range */ +) { + int i, j; + double xmin, xmax, ymin, ymax; + int nn = abs(n); + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + yy[3] = y4; + yy[4] = y5; + yy[5] = y6; + yy[6] = y7; + yy[7] = y8; + yy[8] = y9; + yy[9] = y10; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + if (zero && ymin > 0.0) + ymin = 0.0; + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + NULL, NULL, NULL, NULL, n , + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 10 graphs + optional crosses. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot10p( +double *x, /* X coord */ +double *y1, /* Black */ +double *y2, /* Red */ +double *y3, /* Green */ +double *y4, /* Blue */ +double *y5, /* Yellow */ +double *y6, /* Purple */ +double *y7, /* Brown */ +double *y8, /* Orange */ +double *y9, /* Grey */ +double *y10,/* White */ +int n, /* Number of values */ +double *xp, double *yp, /* And crosses */ +int m) { + int i, j; + double xmin, xmax, ymin, ymax; + int nn = abs(n); + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + yy[3] = y4; + yy[4] = y5; + yy[5] = y6; + yy[6] = y7; + yy[7] = y8; + yy[9] = y9; + yy[5] = y10; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + for (i = 0; i < m; i++) { + if (xp != NULL) { + if (xmin > xp[i]) + xmin = xp[i]; + if (xmax < xp[i]) + xmax = xp[i]; + } + if (yp != NULL) { + if (ymin > yp[i]) + ymin = yp[i]; + if (ymax < yp[i]) + ymax = yp[i]; + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + xp, yp, NULL, NULL, m, + NULL, NULL, NULL, NULL, NULL, 0); +} + + +/* Plot a bunch of vectors + optional crosses */ +/* return 0 on success, -1 on error */ +int do_plot_vec( +double xmin, +double xmax, +double ymin, +double ymax, +double *x1, /* vector start */ +double *y1, +double *x2, /* vector end */ +double *y2, +int n, /* Number of vectors */ +int dowait, +double *x3, /* extra point */ +double *y3, +plot_col *mcols, /* point colors */ +char **mtext, /* notation */ +int m /* Number of points */ +) { + int j; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, dowait, + x1, x2, yy, NULL, n, + x3, y3, mcols, mtext, m, + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Plot a bunch of vectors + optional crosses + optional vectors*/ +/* return 0 on success, -1 on error */ +int do_plot_vec2( +double xmin, +double xmax, +double ymin, +double ymax, +double *x1, /* n vector start */ +double *y1, +double *x2, /* vector end and diagonal cross */ +double *y2, +char **ntext, /* text annotation at cross */ +int n, /* Number of vectors */ +int dowait, +double *x3, /* m extra point */ +double *y3, +plot_col *mcols,/* point colors */ +char **mtext, /* text annotation */ +int m, /* Number of points */ +double *x4, /* o vector start */ +double *y4, +double *x5, /* o vector end */ +double *y5, +plot_col *ocols,/* Vector colors */ +int o /* Number of vectors */ +) { + int j; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, dowait, + x1, x2, yy, ntext, n, + x3, y3, mcols, mtext, m, + x4, y4, x5, y5, ocols, o); +} +/* ********************************** NT version ********************** */ +#ifdef NT + +#include + +#ifdef DODEBUG +# define debugf(xx) printf xx +#else +# define debugf(xx) +#endif + +double plot_ratio = 1.0; +HANDLE plot_th; /* Thread */ +char plot_AppName[] = "PlotWin"; +HWND plot_hwnd = NULL; /* Open only one window per session */ +int plot_signal = 0; /* Signal a key or quit */ + +static LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM); + +/* Thread to handle message processing, so that there is no delay */ +/* when the main thread is doing other things. */ +DWORD WINAPI plot_message_thread(LPVOID lpParameter) { + MSG msg; + WNDCLASS wc; + ATOM arv; + HWND _hwnd; + + // Fill in window class structure with parameters that describe the + // main window. + + wc.style = CS_HREDRAW | CS_VREDRAW; // Class style(s). + wc.lpfnWndProc = MainWndProc; // Function to retrieve messages for windows of this class. + wc.cbClsExtra = 0; // No per-class extra data. + wc.cbWndExtra = 0; // No per-window extra data. + wc.hInstance = NULL; // Application that owns the class. + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_CROSS); + wc.hbrBackground = GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = plot_AppName; + + arv = RegisterClass(&wc); + + if (!arv) { + debugf(("RegisterClass failed, lasterr = %d\n",GetLastError())); + return -1; + } + + _hwnd = CreateWindow( + plot_AppName, + "2D Diagnostic Graph Plot", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + (int)(DEFWWIDTH * plot_ratio + 0.5), + DEFWHEIGHT, + NULL, + NULL, + NULL, // hInstance, + NULL); + + if (!_hwnd) { + debugf(("CreateWindow failed, lasterr = %d\n",GetLastError())); + return -1; + } + + ShowWindow(_hwnd, SW_SHOW); + + plot_hwnd = _hwnd; + + /* Now process messages until we're done */ + for (;;) { + if (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + if (plot_signal == 99) + break; + } + } + + if (UnregisterClass(plot_AppName, NULL) == 0) { + debugf(("UnregisterClass failed, lasterr = %d\n",GetLastError())); + } + + plot_hwnd = NULL; /* Signal it's been deleted */ + + return 0; +} + +/* Superset implementation function: */ +/* return 0 on success, -1 on error */ +/* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */ +/* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */ +/* Vector uses x1, y1 to x2, y2 as a vector with a diagonal cross at x2, y2 all in black, */ +/* with annotation ntext at the cross, */ +/* plus a diagonal cross at x7, y7 in yellow. The color for x7, y7 can be overidden by an */ +/* array of colors mcols, and augmented by optional label text mtext. (x2 != NULL) */ +/* n = number of points/vectors. -ve for reversed X axis */ +/* m = number of extra points (x2,y3 or x7,y7) */ +static int do_plot_imp( + double xmin, double xmax, double ymin, double ymax, /* Bounding box */ + double ratio, /* Aspect ratio of window, X/Y */ + int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */ + double *x1, double *x2, + double *yy[MXGPHS], char **ntext, + int n, + double *x7, double *y7, plot_col *mcols, char **mtext, + int m, + double *x8, double *y8, double *x9, double*y9, plot_col *ocols, + int o +) { + pd.dowait = 10 * dowait; + pd.ratio = ratio; + { + int j; + double xr,yr; + + pd.mnx = xmin; + pd.mny = ymin; + pd.mxx = xmax; + pd.mxy = ymax; + + /* Allow some extra around plot */ + xr = pd.mxx - pd.mnx; + yr = pd.mxy - pd.mny; + if (xr < 1e-6) + xr = 1e-6; + if (yr < 1e-6) + yr = 1e-6; + pd.mnx -= xr/10.0; + pd.mxx += xr/10.0; + pd.mny -= yr/10.0; + pd.mxy += yr/10.0; + + /* Transfer raw point info */ + if (x2 == NULL) + pd.graph = 1; /* 6 graphs + points */ + else + pd.graph = 0; + pd.x1 = x1; + pd.x2 = x2; + for (j = 0; j < MXGPHS; j++) + pd.yy[j] = yy[j]; + pd.ntext = ntext; + pd.n = abs(n); + + if (n < 0) { + double tt; + tt = pd.mxx; + pd.mxx = pd.mnx; + pd.mnx = tt; + pd.revx = 1; + } else { + pd.revx = 0; + } + pd.x7 = x7; + pd.y7 = y7; + pd.mcols = mcols; + pd.mtext = mtext; + pd.m = abs(m); + + pd.x8 = x8; + pd.y8 = y8; + pd.x9 = x9; + pd.y9 = y9; + pd.ocols = ocols; + pd.o = abs(o); + } + + /* ------------------------------------------- */ + /* Setup windows stuff */ + { + + /* It would be nice to reduce number of globals. */ + + /* We don't clean up properly either - ie. don't delete thread etc. */ + + /* Create thread that creats window and processes window messages */ + if (plot_hwnd == NULL) { + + plot_ratio = ratio; + + plot_th = CreateThread(NULL, 0, plot_message_thread, NULL, 0, NULL); + if (plot_th == NULL) { + debugf(("new_athread failed\n")); + return -1; + } + while (plot_hwnd == NULL) + Sleep(50); + } + + plot_signal = 0; + + SetForegroundWindow(plot_hwnd); + + /* Force a repaint with the new data */ + if (!InvalidateRgn(plot_hwnd,NULL,TRUE)) { + debugf(("InvalidateRgn failed, lasterr = %d\n",GetLastError())); + return -1; + } + + if (dowait > 0) { /* Wait for a space key */ + while(plot_signal == 0 && plot_hwnd != NULL) + Sleep(50); + plot_signal = 0; + } else if (dowait < 0) { + Sleep(-dowait * 1000); + } + } + return 0; +} + +void DoPlot(HDC hdc, plot_info *pd); + +static LRESULT CALLBACK MainWndProc( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam +) { + HDC hdc; + PAINTSTRUCT ps; + RECT rect; + + debugf(("Handling message type 0x%x\n",message)); + // Could use Set/GetWindowLong() to pass window class info instead of global pd (beware NULL) + switch(message) { + case WM_PAINT: + debugf(("It's a paint message\n")); + hdc = BeginPaint(hwnd, &ps); + GetClientRect(hwnd, &rect); + + /* Setup the plot info structure for this drawing */ + pd.sx = rect.left; + pd.sy = rect.top; + pd.sw = 1 + rect.right - rect.left; + pd.sh = 1 + rect.bottom - rect.top; + pd.scx = (pd.sw - 10)/(pd.mxx - pd.mnx); + pd.scy = (pd.sh - 10)/(pd.mxy - pd.mny); + + DoPlot(hdc, &pd); + + EndPaint(hwnd, &ps); + + return 0; + + case WM_CHAR: + debugf(("It's a char message, wParam = 0x%x\n",wParam)); + switch(wParam) { + case ' ': /* Space */ + debugf(("It's a SPACE, so signal it\n")); + plot_signal = 1; + return 0; + } + + case WM_CLOSE: + debugf(("It's a close message\n")); + DestroyWindow(hwnd); + return 0; + + case WM_DESTROY: + debugf(("It's a destroy message\n")); + plot_signal = 99; + PostQuitMessage(0); + return 0; + } + + debugf(("It's a message not handled here\n")); + return DefWindowProc(hwnd, message, wParam, lParam); +} + +void +xtick(HDC hdc, plot_info *pdp, double x, char *lab) + { + int xx,yy; + RECT rct; +// GrLine(10 + (int)((x - pdp->mnx) * scx + 0.5), sh - 10 - 5, +// 10 + (int)((x - pdp->mnx) * scx + 0.5), sh - 10 + 5, 1); +// GrTextXY(5 + (int)((x - pdp->mnx) * scx + 0.5), sh - 10 - 10, lab, 1, 0); + + xx = 10 + (int)((x - pdp->mnx) * pdp->scx + 0.5); + yy = pdp->sh - 10; + + MoveToEx(hdc,xx, yy, NULL); + LineTo( hdc,xx, 0); + rct.right = + rct.left = xx; + rct.top = + rct.bottom = yy; + DrawText(hdc, lab, -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP); + } + +void +ytick(HDC hdc, plot_info *pdp, double y, char *lab) + { + int xx,yy; + RECT rct; +// GrLine(5, 10 + (int)((y - pdp->mny) * pdp->scy + 0.5), +// 15, 10 + (int)((y - pdp->mny) * pdp->scy + 0.5), 1); +// GrTextXY(5, pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5), lab, 1, 0); + + xx = 5; + yy = pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5); + MoveToEx(hdc,xx, yy,NULL); + LineTo( hdc,pdp->sw, yy); + rct.right = + rct.left = xx; + rct.top = + rct.bottom = yy; + DrawText(hdc, lab, -1, &rct, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_NOCLIP); + } + +void +loose_label(HDC hdc, plot_info *pdp, double min, double max, void (*pfunc)(HDC hdc, plot_info *pdp, double, char *) +) { + char str[6], temp[20]; + int nfrac; + double d; + double graphmin, graphmax; + double range,x; + + range = nicenum(min-max,0); + d = nicenum(range/(NTICK-1),1); + graphmin = floor(min/d) * d; + graphmax = ceil(max/d) * d; + nfrac = (int)MAX(-floor(log10(d)),0); + sprintf(str,"%%.%df", nfrac); + for (x = graphmin; x < graphmax + 0.5 * d; x += d) { + sprintf(temp,str,x); + pfunc(hdc,pdp,x,temp); + } +} + +void +DoPlot( +HDC hdc, +plot_info *pdp +) { + int i, j; + int lx,ly; /* Last x,y */ + HPEN pen; + + pen = CreatePen(PS_DOT,0,RGB(200,200,200)); + + SaveDC(hdc); + SelectObject(hdc,pen); + + /* Plot horizontal axis */ + if (pdp->revx) + loose_label(hdc, pdp, pdp->mxx, pdp->mnx, xtick); + else + loose_label(hdc, pdp, pdp->mnx, pdp->mxx, xtick); + + /* Plot vertical axis */ + loose_label(hdc, pdp, pdp->mny, pdp->mxy, ytick); + + RestoreDC(hdc,-1); + DeleteObject(pen); + + if (pdp->graph) { /* Up to MXGPHS graphs + crosses */ + int gcolors[MXGPHS][3] = { + { 0, 0, 0}, /* Black */ + { 210, 30, 0}, /* Red */ + { 0, 200, 90}, /* Green */ + { 0, 10, 255}, /* Blue */ + { 200, 200, 0}, /* Yellow */ + { 220, 0, 255}, /* Purple */ + { 136, 86, 68}, /* Brown */ + { 248, 95, 0}, /* Orange */ + { 160, 160, 160}, /* Grey */ + { 220, 220, 220} /* White */ + }; + for (j = MXGPHS-1; j >= 0; j--) { + double *yp = pdp->yy[j]; + + if (yp == NULL) + continue; + + pen = CreatePen(PS_SOLID,ILTHICK,RGB(gcolors[j][0],gcolors[j][1],gcolors[j][2])); + SelectObject(hdc,pen); + + lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)(( yp[0] - pdp->mny) * pdp->scy + 0.5); + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)(( yp[i] - pdp->mny) * pdp->scy + 0.5); + + MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly, NULL); + LineTo(hdc, 10 + cx, pdp->sh - 10 - cy); +#ifdef CROSSES + MoveToEx(hdc, 10 + cx - 5, pdp->sh - 10 - cy - 5, NULL); + LineTo(hdc, 10 + cx + 5, pdp->sh - 10 - cy + 5); + GrLine(10 + cx + 5, pdp->sh - 10 - cy - 5); + LineTo(hdc, 10 + cx - 5, pdp->sh - 10 - cy + 5); +#endif + lx = cx; + ly = cy; + } + DeleteObject(pen); + } + + } else { /* Vectors with cross */ + + pen = CreatePen(PS_SOLID,ILTHICK,RGB(0,0,0)); + SelectObject(hdc,pen); + + if (pdp->ntext != NULL) { + HFONT fon; + + fon = CreateFont(12, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, ANSI_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + FF_DONTCARE, NULL); + + if (fon == NULL) + fprintf(stderr,"plot: CreateFont returned NULL\n"); + else { + SelectObject(hdc,fon); + DeleteObject(fon); + } + } + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + + lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5); + + MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly, NULL); + LineTo(hdc, 10 + cx, pdp->sh - 10 - cy); + + MoveToEx(hdc, 10 + cx - 5, pdp->sh - 10 - cy - 5, NULL); + LineTo(hdc, 10 + cx + 5, pdp->sh - 10 - cy + 5); + MoveToEx(hdc, 10 + cx + 5, pdp->sh - 10 - cy - 5, NULL); + LineTo(hdc, 10 + cx - 5, pdp->sh - 10 - cy + 5); + + if (pdp->ntext != NULL) { + RECT rct; + rct.right = + rct.left = 10 + cx + 10; + rct.top = + rct.bottom = pdp->sh - 10 - cy + 10; + DrawText(hdc, pdp->ntext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP); + } + } + DeleteObject(pen); + } + + /* Extra points */ + if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) { + pen = CreatePen(PS_SOLID,ILTHICK,RGB(210,150,0)); + SelectObject(hdc,pen); + + if (pdp->mtext != NULL) { + HFONT fon; + + + fon = CreateFont(12, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, ANSI_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + FF_DONTCARE, NULL); + + if (fon == NULL) + fprintf(stderr,"plot: CreateFont returned NULL\n"); + else { + SelectObject(hdc,fon); + DeleteObject(fon); + } + } + + for (i = 0; i < pdp->m; i++) { + lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5); + + if (pdp->mcols != NULL) { + int rgb[3]; + + for (j = 0; j < 3; j++) + rgb[j] = (int)(pdp->mcols[i].rgb[j] * 255.0 + 0.5); + + DeleteObject(pen); + pen = CreatePen(PS_SOLID,ILTHICK,RGB(rgb[0],rgb[1],rgb[2])); + SelectObject(hdc,pen); + + if (pdp->mtext != NULL) + SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2])); + } + MoveToEx(hdc, 10 + lx - 5, pdp->sh - 10 - ly, NULL); + LineTo(hdc, 10 + lx + 5, pdp->sh - 10 - ly); + MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly - 5, NULL); + LineTo(hdc, 10 + lx, pdp->sh - 10 - ly + 5); + + if (pdp->mtext != NULL) { + RECT rct; + rct.right = + rct.left = 10 + lx + 10; + rct.top = + rct.bottom = pdp->sh - 10 - ly - 10; + DrawText(hdc, pdp->mtext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP); + } + } + DeleteObject(pen); + } + /* Extra vectors */ + if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) { + pen = CreatePen(PS_SOLID,ILTHICK,RGB(150,255,255)); + SelectObject(hdc,pen); + + for (i = 0; i < pdp->o; i++) { + int cx,cy; + + lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5); + + if (pdp->ocols != NULL) { + int rgb[3]; + + for (j = 0; j < 3; j++) + rgb[j] = (int)(pdp->ocols[i].rgb[j] * 255.0 + 0.5); + + DeleteObject(pen); + pen = CreatePen(PS_SOLID,ILTHICK,RGB(rgb[0],rgb[1],rgb[2])); + SelectObject(hdc,pen); + + if (pdp->mtext != NULL) + SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2])); + } + MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly, NULL); + LineTo(hdc, 10 + cx, pdp->sh - 10 - cy); + } + DeleteObject(pen); + } + +// while(!kbhit()); + } + +#else /* !NT */ + +/* ************************** APPLE OSX Cocoa version ****************** */ +#ifdef __APPLE__ + +#include +#include + +#ifndef CGFLOAT_DEFINED +#ifdef __LP64__ +typedef double CGFloat; +#else +typedef float CGFloat; +#endif /* defined(__LP64__) */ +#endif + +#ifdef DODEBUG +# define debugf(xx) printf xx +#else +# define debugf(xx) +#endif + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +@class PLWin; +@class PLView; + +/* Our static instance variables */ +typedef struct { + PLWin *window; /* NSWindow */ + PLView *view; /* NSTextField */ + volatile int plot_signal; /* Signal a key or quit */ +} cntx_t; + +/* Global plot instanc */ + +cntx_t *plot_cx = NULL; + +// - - - - - - - - - - - - - - - - - - - - - - - - - +@interface PLView : NSView { + cntx_t *cntx; +} +- (void)setCntx:(cntx_t *)cntx; +@end + +@implementation PLView + +- (void)setCntx:(cntx_t *)val { + cntx = val; +} + +/* This function does the work */ +static void DoPlot(NSRect *rect, plot_info *pdp); + +- (void)drawRect:(NSRect)rect { + + /* Use global plot data struct for now */ + DoPlot(&rect, &pd); +} + +@end + +// - - - - - - - - - - - - - - - - - - - - - - - - - + +@interface PLWin : NSWindow { + cntx_t *cntx; +} +- (void)setCntx:(cntx_t *)cntx; +@end + +@implementation PLWin + +- (void)setCntx:(cntx_t *)val { + cntx = val; +} + +- (BOOL)canBecomeMainWindow { + return YES; +} + +- (void)keyDown:(NSEvent *)event { + const char *chars; + + chars = [[event characters] UTF8String]; +// printf("Got Window KeyDown type %d char %s\n",(int)[event type], chars); + + if (chars[0] == ' ') { +// printf("Set plot_signal = 1\n"); + plot_cx->plot_signal = 1; + } +} + +- (BOOL)windowShouldClose:(id)sender { +// printf("Got Window windowShouldClose\n"); + + [NSApp terminate: nil]; + return YES; +} + +@end + +/* Create our window */ +static void create_my_win(cntx_t *cx) { + NSRect wRect; + + /* Create Window */ + wRect.origin.x = 100; + wRect.origin.y = 100; + wRect.size.width = (int)(DEFWWIDTH*pd.ratio+0.5); + wRect.size.height = DEFWHEIGHT; + + cx->window = [[PLWin alloc] initWithContentRect: wRect + styleMask: (NSTitledWindowMask | + NSClosableWindowMask | + NSMiniaturizableWindowMask | + NSResizableWindowMask) + backing: NSBackingStoreBuffered + defer: YES + screen: nil]; /* Main screen */ + + [cx->window setBackgroundColor: [NSColor whiteColor]]; + + [cx->window setLevel: NSMainMenuWindowLevel]; // ~~99 + + [cx->window setTitle: @"PlotWin"]; + + /* Use our view for the whole window to draw plot */ + cx->view = [PLView new]; + [cx->view setCntx:(void *)cx]; + [cx->window setContentView: cx->view]; + + [cx->window makeKeyAndOrderFront: nil]; + +// [cx->window makeMainWindow]; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* + Cocoa NSApp is pretty horrible - it will only get user events + if created and run in the main thread. So the only way we could + decouble the windows from the application would be to intercept + main() and create a secondary thread to run the appication while + leaving main() in reserve for creating an NSApp and windows. + + Instead we poll events for a while and then go back to the main application. + */ + +/* Superset implementation function: */ +/* return 0 on success, -1 on error */ +/* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */ +/* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */ +/* Vector uses x1, y1 to x2, y2 as a vector with a diagonal cross at x2, y2 all in black, */ +/* with annotation ntext at the cross, */ +/* plus a diagonal cross at x7, y7 in yellow. The color for x7, y7 can be overidden by an */ +/* array of colors mcols, and augmented by optional label text mtext. (x2 != NULL) */ +/* n = number of points/vectors. -ve for reversed X axis */ +/* m = number of extra points (x2,y3 or x7,y7) */ +static int do_plot_imp( + double xmin, double xmax, double ymin, double ymax, /* Bounding box */ + double ratio, /* Aspect ratio of window, X/Y */ + int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */ + double *x1, double *x2, + double *yy[MXGPHS], char **ntext, + int n, + double *x7, double *y7, plot_col *mcols, char **mtext, + int m, + double *x8, double *y8, double *x9, double*y9, plot_col *ocols, + int o +) { + /* Put information in global pd */ + { + int j; + double xr,yr; + + pd.dowait = dowait; + pd.ratio = ratio; + + pd.mnx = xmin; + pd.mny = ymin; + pd.mxx = xmax; + pd.mxy = ymax; + + /* Allow some extra arround plot */ + xr = pd.mxx - pd.mnx; + yr = pd.mxy - pd.mny; + if (xr < 1e-6) + xr = 1e-6; + if (yr < 1e-6) + yr = 1e-6; + pd.mnx -= xr/10.0; + pd.mxx += xr/10.0; + pd.mny -= yr/10.0; + pd.mxy += yr/10.0; + + /* Transfer raw point info */ + if (x2 == NULL) + pd.graph = 1; /* 6 graphs + points */ + else + pd.graph = 0; + pd.x1 = x1; + pd.x2 = x2; + for (j = 0; j < MXGPHS; j++) + pd.yy[j] = yy[j]; + pd.ntext = ntext; + pd.n = abs(n); + + if (n < 0) { + double tt; + tt = pd.mxx; + pd.mxx = pd.mnx; + pd.mnx = tt; + pd.revx = 1; + } else { + pd.revx = 0; + } + pd.x7 = x7; + pd.y7 = y7; + pd.mcols = mcols; + pd.mtext = mtext; + pd.m = abs(m); + + pd.x8 = x8; + pd.y8 = y8; + pd.x9 = x9; + pd.y9 = y9; + pd.ocols = ocols; + pd.o = abs(o); + } + + /* If needed, create the indow */ + if (plot_cx == NULL) { + + /* If there is no NSApp */ + /* (This should go in a common library) */ + /* Note that we don't actually clean this up on exit - */ + /* possibly we can't. */ + if (NSApp == nil) { + static NSAutoreleasePool *pool = nil; + ProcessSerialNumber psn = { 0, 0 }; + + /* Transform the process so that the desktop interacts with it properly. */ + /* We don't need resources or a bundle if we do this. */ + if (GetCurrentProcess(&psn) == noErr) { + OSStatus stat; + if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn, + kProcessTransformToForegroundApplication)) != noErr) { +// fprintf(stderr,"TransformProcess failed with code %d\n",stat); + } else { +// fprintf(stderr,"TransformProcess suceeded\n"); + } + } + + + pool = [NSAutoreleasePool new]; + [NSApplication sharedApplication]; /* Creates NSApp */ + [NSApp finishLaunching]; + + /* We seem to need this, because otherwise we don't get focus automatically */ + [NSApp activateIgnoringOtherApps: YES]; + } + + if ((plot_cx = (cntx_t *)calloc(sizeof(cntx_t), 1)) == NULL) + error("new_dispwin: Malloc failed (cntx_t)\n"); + + create_my_win(plot_cx); + + } else { /* Trigger an update */ + [plot_cx->view setNeedsDisplay: YES ]; + } + + /* Wait until the events are done */ + { + NSEvent *event; + double tot; + NSDate *to; + /* We're creating and draining a pool here to ensure that all the */ + /* auto release objects get drained when we're finished (?) */ + NSAutoreleasePool *tpool = [NSAutoreleasePool new]; + + if (dowait > 0) { /* Wait for a space key */ + tot = 24.0 * 60.0 * 60.0; + } else if (dowait < 0) { + tot = (double)-dowait; + } else { + tot = 0.1; + } + to = [NSDate dateWithTimeIntervalSinceNow:tot]; /* autorelease ? */ + plot_cx->plot_signal = 0; + for (;plot_cx->plot_signal == 0;) { + /* Hmm. Assume event is autorelease */ + if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:to inMode:NSDefaultRunLoopMode dequeue:YES]) != nil) { + [NSApp sendEvent:event]; + } else { + break; + } + } + [tpool release]; + } + return 0; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* Cleanup code (not called) */ + +static void cleanup() { + [plot_cx->window release]; /* Take down the plot window */ + free(plot_cx); + plot_cx = NULL; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* Utility to draw text in Cocoa with centering */ +/* Size is points */ +/* Flags 0x1 == horizontal center */ +/* Flags 0x2 == vertical center */ +static void ADrawText(NSColor *col, float size, float x, float y, int flags, char *text) { + NSFont* font = [NSFont systemFontOfSize:size]; + NSDictionary *att = [NSDictionary dictionaryWithObjectsAndKeys: + font, NSFontAttributeName, + col, NSForegroundColorAttributeName, + nil]; + NSString *str = [[NSString alloc] initWithUTF8String: text]; + + if (flags != 0x0) { + NSSize size; + + /* Figure out how big it will be */ + size = [str sizeWithAttributes: att ]; + if (flags & 0x1) { + double w = fabs(size.width); + x -= 0.5 * w; + } + if (flags & 0x2) { + double h = fabs(size.height); + y -= 0.5 * h; + } + } + + [str drawAtPoint: NSMakePoint(x, y) withAttributes: att]; + [str release]; /* Others are autorelease */ +} + +/* Draw a line */ +/* We re-use the same path so that we can set the dash style */ +static void ADrawLine(NSBezierPath *path, float xs, float ys, float xe, float ye) { + [path removeAllPoints ]; + [path moveToPoint:NSMakePoint(xs, ys)]; + [path lineToPoint:NSMakePoint(xe, ye)]; + [path stroke]; +} + +/* Draw X axis grid lines */ +void +xtick( +plot_info *pdp, +NSBezierPath *path, +NSColor *lcol, +NSColor *tcol, +double x, char *lab +) { + float xx, yy; + + xx = 20.0 + (x - pdp->mnx) * pdp->scx; + yy = 20.0; + + [lcol setStroke]; /* There is a bug in 10.4 which resets this after each stroke */ + ADrawLine(path, xx, yy, xx, (float)pdp->sh); + ADrawText(tcol, 10.0, xx, 5.0, 0x1, lab); +} + +/* Draw Y axis grid lines */ +void +ytick( +plot_info *pdp, +NSBezierPath *path, +NSColor *lcol, +NSColor *tcol, +double y, char *lab +) { + float xx, yy; + + xx = 20.0; + yy = 20.0 + (y - pdp->mny) * pdp->scy; + + [lcol setStroke]; /* There is a bug in 10.4 which resets this after each stroke */ + ADrawLine(path, xx, yy, (float)pdp->sw, yy); + ADrawText(tcol, 10.0, 3.0, yy, 0x2, lab); +} + +void +loose_label( +plot_info *pdp, +NSBezierPath *path, +NSColor *lcol, +NSColor *tcol, +double min, double max, +void (*pfunc)(plot_info *pdp, NSBezierPath *path, NSColor *lcol, NSColor *tcol, double, char *) +) { + char str[6], temp[20]; + int nfrac; + double d; + double graphmin, graphmax; + double range,x; + + range = nicenum(min-max,0); + d = nicenum(range/(NTICK-1),1); + graphmin = floor(min/d) * d; + graphmax = ceil(max/d) * d; + nfrac = (int)MAX(-floor(log10(d)),0); + sprintf(str,"%%.%df", nfrac); + for (x = graphmin; x < graphmax + 0.5 * d; x += d) { + sprintf(temp,str,x); + pfunc(pdp, path, lcol, tcol, x, temp); + } +} + +/* Called from within view to plot overall graph */ +static void DoPlot(NSRect *rect, plot_info *pdp) { + int i, j; + int lx,ly; /* Last x,y */ + CGFloat dash_list[2] = {7.0, 2.0}; + /* Note path and tcol are autorelease */ + NSBezierPath *path = [NSBezierPath bezierPath]; /* Path to use */ + NSColor *lcol = nil; + NSColor *tcol = nil; + + /* Setup the plot info structure for this drawing */ + /* Note port rect is raster like, pdp/Quartz2D is Postscript like */ + pdp->sx = rect->origin.x; + pdp->sy = rect->origin.y; + pdp->sw = rect->size.width; + pdp->sh = rect->size.height; + pdp->scx = (pdp->sw - 20)/(pdp->mxx - pdp->mnx); + pdp->scy = (pdp->sh - 20)/(pdp->mxy - pdp->mny); + + /* Plot the axis lines */ + [path setLineWidth:1.0]; + [path setLineDash: dash_list count: 2 phase: 0.0 ]; /* Set dashed lines for axes */ + + /* Make sure text is black */ + tcol = [NSColor colorWithCalibratedRed: 0.0 + green: 0.0 + blue: 0.0 + alpha: 1.0]; + + lcol = [NSColor colorWithCalibratedRed:0.7 green: 0.7 blue:0.7 alpha: 1.0]; /* Grey */ + + /* Plot horizontal axis */ + if (pdp->revx) + loose_label(pdp, path, lcol, tcol, pdp->mxx, pdp->mnx, xtick); + else + loose_label(pdp, path, lcol, tcol, pdp->mnx, pdp->mxx, xtick); + + /* Plot vertical axis */ + loose_label(pdp, path, lcol, tcol, pdp->mny, pdp->mxy, ytick); + + /* Set to non-dashed line */ + [path setLineWidth: LTHICK]; + [path setLineDash: NULL count: 0 phase: 0.0 ]; + + if (pdp->graph) { /* Up to 6 graphs */ + int gcolors[MXGPHS][3] = { + { 0, 0, 0}, /* Black */ + { 210, 30, 0}, /* Red */ + { 0, 200, 90}, /* Green */ + { 0, 10, 255}, /* Blue */ + { 200, 200, 0}, /* Yellow */ + { 220, 0, 255}, /* Purple */ + { 136, 86, 68}, /* Brown */ + { 248, 95, 0}, /* Orange */ + { 160, 160, 160}, /* Grey */ + { 220, 220, 220} /* White */ + }; + for (j = MXGPHS-1; j >= 0; j--) { + double *yp = pdp->yy[j]; + + if (yp == NULL) + continue; + [[NSColor colorWithCalibratedRed: gcolors[j][0]/255.0 + green: gcolors[j][1]/255.0 + blue: gcolors[j][2]/255.0 + alpha: 1.0] setStroke]; + + lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)(( yp[0] - pdp->mny) * pdp->scy + 0.5); + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)(( yp[i] - pdp->mny) * pdp->scy + 0.5); + + ADrawLine(path, 20.0 + lx, 20.0 + ly, 20 + cx, 20.0 + cy); +#ifdef CROSSES + ADrawLine(path, 20.0 + cx - 5, 20.0 - cy - 5, 20.0 + cx + 5, 20.0 + cy + 5); + ADrawLine(path, 20.0 + cx + 5, 20.0 - cy - 5, 20.0 + cx - 5, 20.0 + cy + 5); +#endif + lx = cx; + ly = cy; + } + } + + } else { /* Vectors */ + [[NSColor colorWithCalibratedRed: 0.0 + green: 0.0 + blue: 0.0 + alpha: 1.0] setStroke]; + if (pdp->ntext != NULL) { + tcol = [NSColor colorWithCalibratedRed: 0.0 + green: 0.0 + blue: 0.0 + alpha: 1.0]; + } + for (i = 0; i < pdp->n; i++) { + int cx,cy; + + lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5); + + ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy); + + ADrawLine(path, 20.0 + cx - 5, 20.0 + cy - 5, 20.0 + cx + 5, 20.0 + cy + 5); + ADrawLine(path, 20.0 + cx + 5, 20.0 + cy - 5, 20.0 + cx - 5, 20.0 + cy + 5); + + if (pdp->ntext != NULL) + ADrawText(tcol, 9.0, 20.0 + cx + 9, 20.0 + cy - 7, 0x1, pdp->ntext[i]); + } + } + + /* Extra points */ + if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) { + [[NSColor colorWithCalibratedRed: 0.82 /* Orange ? */ + green: 0.59 + blue: 0.0 + alpha: 1.0] setStroke]; + + for (i = 0; i < pdp->m; i++) { + + if (pdp->mcols != NULL) { + [[NSColor colorWithCalibratedRed: pdp->mcols[i].rgb[0] + green: pdp->mcols[i].rgb[1] + blue: pdp->mcols[i].rgb[2] + alpha: 1.0] setStroke]; + + if (pdp->mtext != NULL) { + tcol = [NSColor colorWithCalibratedRed: pdp->mcols[i].rgb[0] + green: pdp->mcols[i].rgb[1] + blue: pdp->mcols[i].rgb[2] + alpha: 1.0]; + } + } + lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5); + + ADrawLine(path, 20.0 + lx - 5, 20.0 + ly, 20.0 + lx + 5, 20.0 + ly); + ADrawLine(path, 20.0 + lx, 20.0 + ly - 5, 20.0 + lx, 20.0 + ly + 5); + + if (pdp->mtext != NULL) { + ADrawText(tcol, 9.0, 20.0 + lx + 9, 20.0 + ly + 7, 0x1, pdp->mtext[i]); + } + } + } + + /* Extra vectors */ + if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) { + [[NSColor colorWithCalibratedRed: 0.5 /* Light blue */ + green: 0.9 + blue: 0.9 + alpha: 1.0] setStroke]; + + for (i = 0; i < pdp->o; i++) { + int cx,cy; + + if (pdp->ocols != NULL) { + [[NSColor colorWithCalibratedRed: pdp->ocols[i].rgb[0] + green: pdp->ocols[i].rgb[1] + blue: pdp->ocols[i].rgb[2] + alpha: 1.0] setStroke]; + if (pdp->mtext != NULL) { + tcol = [NSColor colorWithCalibratedRed: pdp->ocols[i].rgb[0] + green: pdp->ocols[i].rgb[1] + blue: pdp->ocols[i].rgb[2] + alpha: 1.0]; + } + } + lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5); + + ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy); + } + } +} + +#else /* Assume UNIX + X11 */ +/* ********************************** X11 version ********************** */ + +/* !!!! There is a problem if the user closes the window - an X11 error results */ +/* This seems to happen before a DestroyNotify !. How to fix ??? !!!! */ + +#include +#include + +#ifdef DODEBUG +# define debugf(xx) printf xx +#else +# define debugf(xx) +#endif + +void DoPlot(Display *mydisplay, Window mywindow, GC mygc, plot_info *pdp); + +/* Superset implementation function: */ +/* return 0 on success, -1 on error */ +/* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */ +/* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */ +/* Vector uses x1, y1 to x2, y2 as a vector with a diagonal cross at x2, y2 all in black, */ +/* with annotation ntext at the cross, */ +/* plus a diagonal cross at x7, y7 in yellow. The color for x7, y7 can be overidden by an */ +/* array of colors mcols, and augmented by optional label text mtext. (x2 != NULL) */ +/* n = number of points/vectors. -ve for reversed X axis */ +/* m = number of extra points (x2,y3 or x7,y7) */ +static int do_plot_imp( + double xmin, double xmax, double ymin, double ymax, /* Bounding box */ + double ratio, /* Aspect ratio of window, X/Y */ + int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */ + double *x1, double *x2, + double *yy[MXGPHS], char **ntext, + int n, + double *x7, double *y7, plot_col *mcols, char **mtext, + int m, + double *x8, double *y8, double *x9, double*y9, plot_col *ocols, + int o +) { + { + int j; + double xr,yr; + + pd.dowait = dowait; + pd.ratio = ratio; + + pd.mnx = xmin; + pd.mny = ymin; + pd.mxx = xmax; + pd.mxy = ymax; + + /* Allow some extra arround plot */ + xr = pd.mxx - pd.mnx; + yr = pd.mxy - pd.mny; + if (xr < 1e-6) + xr = 1e-6; + if (yr < 1e-6) + yr = 1e-6; + pd.mnx -= xr/10.0; + pd.mxx += xr/10.0; + pd.mny -= yr/10.0; + pd.mxy += yr/10.0; + + /* Transfer raw point info */ + if (x2 == NULL) + pd.graph = 1; /* 6 graphs + points */ + else + pd.graph = 0; + pd.x1 = x1; + pd.x2 = x2; + for (j = 0; j < MXGPHS; j++) + pd.yy[j] = yy[j]; + pd.ntext = ntext; + pd.n = abs(n); + + if (n < 0) { + double tt; + tt = pd.mxx; + pd.mxx = pd.mnx; + pd.mnx = tt; + pd.revx = 1; + } else { + pd.revx = 0; + } + pd.x7 = x7; + pd.y7 = y7; + pd.mcols = mcols; + pd.mtext = mtext; + pd.m = abs(m); + + pd.x8 = x8; + pd.y8 = y8; + pd.x9 = x9; + pd.y9 = y9; + pd.ocols = ocols; + pd.o = abs(o); + } + + { + /* stuff for X windows */ + char plot[] = {"plot"}; + static Display *mydisplay = NULL; + static Window mywindow = -1; + int dorefresh = 1; + GC mygc; + XEvent myevent; + XSizeHints myhint; + XWindowAttributes mywattributes; + int myscreen; + unsigned long myforeground,mybackground; + int done; + + /* open the display */ + if (mydisplay == NULL) { + mydisplay = XOpenDisplay(""); + if(!mydisplay) + error("Unable to open display"); + dorefresh = 0; + } + myscreen = DefaultScreen(mydisplay); + mybackground = WhitePixel(mydisplay,myscreen); + myforeground = BlackPixel(mydisplay,myscreen); + + myhint.x = 100; + myhint.y = 100; + myhint.width = (int)(DEFWWIDTH * ratio + 0.5); + myhint.height = DEFWHEIGHT; + myhint.flags = PPosition | USSize; + + debugf(("Opened display OK\n")); + + if (mywindow == -1) { + debugf(("Opening window\n")); + mywindow = XCreateSimpleWindow(mydisplay, + DefaultRootWindow(mydisplay), + myhint.x,myhint.y,myhint.width,myhint.height, + 5, myforeground,mybackground); + XSetStandardProperties(mydisplay,mywindow,plot,plot,None, + NULL,0, &myhint); + } + + mygc = XCreateGC(mydisplay,mywindow,0,0); + XSetBackground(mydisplay,mygc,mybackground); + XSetForeground(mydisplay,mygc,myforeground); + + XSelectInput(mydisplay,mywindow, + KeyPressMask | ExposureMask | StructureNotifyMask); + + if (dorefresh) { + XExposeEvent ev; + + ev.type = Expose; + ev.display = mydisplay; + ev.send_event = True; + ev.window = mywindow; + ev.x = 0; + ev.y = 0; + ev.width = myhint.width; + ev.height = myhint.height; + ev.count = 0; + + XClearWindow(mydisplay, mywindow); + XSendEvent(mydisplay, mywindow, False, ExposureMask, (XEvent *)&ev); + + } else { + XMapRaised(mydisplay,mywindow); + debugf(("Raised window\n")); + } + + /* Main event loop */ + debugf(("About to enter main loop\n")); + done = 0; + while(done == 0) { + XNextEvent(mydisplay,&myevent); + switch(myevent.type) { + case Expose: + if(myevent.xexpose.count == 0) { /* Repare the exposed region */ + XGetWindowAttributes(mydisplay, mywindow, & mywattributes); + /* Setup the plot info structure for this drawing */ + pd.sx = mywattributes.x; + pd.sy = mywattributes.y; + pd.sw = mywattributes.width; + pd.sh = mywattributes.height; + pd.scx = (pd.sw - 10)/(pd.mxx - pd.mnx); + pd.scy = (pd.sh - 10)/(pd.mxy - pd.mny); + + DoPlot(mydisplay,mywindow, mygc, &pd); + + if (pd.dowait <= 0) { /* Don't wait */ + if (pd.dowait < 0) + sleep(-pd.dowait); + debugf(("Not waiting, so set done=1\n")); + done = 1; + } + } + break; + case MappingNotify: + XRefreshKeyboardMapping(&myevent.xmapping); + break; + case KeyPress: + debugf(("Got a button press\n")); + done = 1; + break; + } + } + debugf(("About to close display\n")); + XFreeGC(mydisplay,mygc); +// XDestroyWindow(mydisplay,mywindow); +// XCloseDisplay(mydisplay); + debugf(("finished\n")); + } + return 0; +} + +/* Draw X axis grid lines */ +void +xtick( +Display *mydisplay, +Window mywindow, +GC mygc, +plot_info *pdp, +double x, char *lab +) { + int xx,yy; + + xx = 10 + (int)((x - pdp->mnx) * pdp->scx + 0.5); + yy = pdp->sh - 10; + + XDrawLine(mydisplay, mywindow, mygc, xx, yy, xx, 0); + XDrawImageString(mydisplay, mywindow, mygc, xx-6, yy, lab, strlen(lab)); +} + +/* Draw Y axis grid lines */ +void +ytick( +Display *mydisplay, +Window mywindow, +GC mygc, +plot_info *pdp, +double y, char *lab +) { + int xx,yy; + + xx = 5; + yy = pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5); + + XDrawLine(mydisplay, mywindow, mygc, xx, yy, pdp->sw, yy); + XDrawImageString(mydisplay, mywindow, mygc, xx, yy+4, lab, strlen(lab)); +} + +void +loose_label( +Display *mydisplay, +Window mywindow, +GC mygc, +plot_info *pdp, +double min, double max, +void (*pfunc)(Display *mydisplay, Window mywindow, GC mygc, plot_info *pdp, double, char *) +) { + char str[6], temp[20]; + int nfrac; + double d; + double graphmin, graphmax; + double range,x; + + range = nicenum(min-max,0); + d = nicenum(range/(NTICK-1),1); + graphmin = floor(min/d) * d; + graphmax = ceil(max/d) * d; + nfrac = (int)MAX(-floor(log10(d)),0); + sprintf(str,"%%.%df", nfrac); + for (x = graphmin; x < graphmax + 0.5 * d; x += d) { + sprintf(temp,str,x); + pfunc(mydisplay, mywindow, mygc, pdp, x, temp); + } +} + +void +DoPlot( +Display *mydisplay, +Window mywindow, +GC mygc, +plot_info *pdp +) { + int i, j; + int lx,ly; /* Last x,y */ + char dash_list[2] = {5, 1}; + Colormap mycmap; + XColor col; + + mycmap = DefaultColormap(mydisplay, 0); + col.red = col.green = col.blue = 150 * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + + /* Set dashed lines for axes */ + XSetLineAttributes(mydisplay, mygc, 1, LineOnOffDash, CapButt, JoinBevel); + XSetDashes(mydisplay, mygc, 0, dash_list, 2); + // ~~ doesn't seem to work. Why ? + + /* Plot horizontal axis */ + if (pdp->revx) + loose_label(mydisplay, mywindow, mygc, pdp, pdp->mxx, pdp->mnx, xtick); + else + loose_label(mydisplay, mywindow, mygc, pdp, pdp->mnx, pdp->mxx, xtick); + + /* Plot vertical axis */ + loose_label(mydisplay, mywindow, mygc, pdp, pdp->mny, pdp->mxy, ytick); + + if (pdp->graph) { /* Up to 10 graphs */ + for (j = MXGPHS-1; j >= 0; j--) { + double *yp = pdp->yy[j]; + + if (yp == NULL) + continue; + + col.red = gcolors[j][0] * 256; + col.green = gcolors[j][1] * 256; + col.blue = gcolors[j][2] * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel); + + lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)(( yp[0] - pdp->mny) * pdp->scy + 0.5); + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)(( yp[i] - pdp->mny) * pdp->scy + 0.5); + + XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy); +#ifdef CROSSES + + XDrawLine(mydisplay, mywindow, mygc, 10 + cx - 5, pdp->sh - 10 - cy - 5, 10 + cx + 5, pdp->sh - 10 - cy + 5); + XDrawLine(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy - 5, 10 + cx - 5, pdp->sh - 10 - cy + 5); +#endif + lx = cx; + ly = cy; + } + } + + } else { /* Vectors */ + + col.red = col.green = col.blue = 0 * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel); + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + + lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5); + + XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy); + + XDrawLine(mydisplay, mywindow, mygc, 10 + cx - 5, pdp->sh - 10 - cy - 5, 10 + cx + 5, pdp->sh - 10 - cy + 5); + XDrawLine(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy - 5, 10 + cx - 5, pdp->sh - 10 - cy + 5); + + if (pdp->ntext != NULL) + XDrawImageString(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy + 7, + pdp->ntext[i], strlen(pdp->ntext[i])); + } + } + + /* Extra points */ + if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) { + col.red = 210 * 256; col.green = 150 * 256; col.blue = 0 * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel); + + for (i = 0; i < pdp->m; i++) { + lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5); + + if (pdp->mcols != NULL) { + col.red = (int)(pdp->mcols[i].rgb[0] * 65535.0 + 0.5); + col.green = (int)(pdp->mcols[i].rgb[1] * 65535.0 + 0.5); + col.blue = (int)(pdp->mcols[i].rgb[2] * 65535.0 + 0.5); + + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + + } + XDrawLine(mydisplay, mywindow, mygc, 10 + lx - 5, pdp->sh - 10 - ly, + 10 + lx + 5, pdp->sh - 10 - ly); + XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly - 5, + 10 + lx, pdp->sh - 10 - ly + 5); + + if (pdp->mtext != NULL) + XDrawImageString(mydisplay, mywindow, mygc, 10 + lx + 5, pdp->sh - 10 - ly - 7, + pdp->mtext[i], strlen(pdp->mtext[i])); + } + } + + /* Extra vectors */ + if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) { + col.red = 150 * 256; col.green = 255 * 256; col.blue = 255 * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel); + + for (i = 0; i < pdp->o; i++) { + int cx,cy; + + lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5); + + if (pdp->ocols != NULL) { + col.red = (int)(pdp->ocols[i].rgb[0] * 65535.0 + 0.5); + col.green = (int)(pdp->ocols[i].rgb[1] * 65535.0 + 0.5); + col.blue = (int)(pdp->ocols[i].rgb[2] * 65535.0 + 0.5); + + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + + } + + XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy); + } + } +} + +#endif /* UNIX + X11 */ +#endif /* !NT */ +/***********************************************************************/ + + +/* Nice graph labeling functions */ + +#define expt(a,n) pow(a,(double)(n)) + +double nicenum(double x, int round) { + int ex; + double f; + double nf; +// printf("nocenum called with %f and %d\n",x,round); + if (x < 0.0) + x = -x; + ex = (int)floor(log10(x)); +// printf("ex = %d\n",ex); + f = x/expt(10.0,ex); +// printf("f = %f\n",f); + if (round) { + if (f < 1.5) nf = 1.0; + else if (f < 3.0) nf = 2.0; + else if (f < 7.0) nf = 5.0; + else nf = 10.0; + } else { + if (f < 1.0) nf = 1.0; + else if (f < 2.0) nf = 2.0; + else if (f < 5.0) nf = 5.0; + else nf = 10.0; + } +// printf("nf = %f\n",nf); +// printf("about to return %f\n",(nf * expt(10.0, ex))); + return (nf * expt(10.0, ex)); +} + +/* ---------------------------------------------------------------- */ +#ifdef STANDALONE_TEST +/* test code */ + +// ~~99 +#define TEST_NON_CONSOLE /* Version that works from command line and GUI */ +// May have to add link flag -Wl,-subsystem,windows +// since MingW is stupid about noticing WinMain or pragma + +//#include +//#include +#include +//#include + + +#ifdef NEVER +/* Append debugging string to log.txt */ +static void dprintf(char *fmt, ...) { + FILE *fp = NULL; + if ((fp = fopen("log.txt", "a+")) != NULL) { + va_list args; + va_start(args, fmt); + vfprintf(fp, fmt, args); + fflush(fp); + fclose(fp); + va_end(args); + } +} +#endif // NEVER + +#ifdef NEVER /* Other non-working enable console output code */ +{ + /* This clever code have been found at: + Adding Console I/O to a Win32 GUI App + Windows Developer Journal, December 1997 + http://dslweb.nwnexus.com/~ast/dload/guicon.htm + Andrew Tucker's Home Page */ + + /* This is not so clever, since it doesn't work... */ + + // redirect unbuffered STDOUT to the console + long lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE); + int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + FILE *fp = _fdopen(hConHandle, "w"); + *stdout = *fp; + setvbuf(stdout, NULL, _IONBF, 0); + + // redirect unbuffered STDIN to the console + lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "r" ); + *stdin = *fp; + setvbuf(stdin, NULL, _IONBF, 0); + + // redirect unbuffered STDERR to the console + lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stderr = *fp; + setvbuf(stderr, NULL, _IONBF, 0); + + +} +#endif // NEVER + +#ifdef NEVER +// ~~~~~~~~~~~~~ +// AllocConsole(); + { + ULONG pbi[6]; + ULONG ulSize = 0; + LONG (WINAPI *NtQueryInformationProcess)(HANDLE ProcessHandle, + ULONG ProcessInformationClass, + PVOID ProcessInformation, + ULONG ProcessInformationLength, + PULONG ReturnLength); + + BOOL (WINAPI *AttachConsole)(DWORD dwProcessId); + + *(FARPROC *)&NtQueryInformationProcess = + GetProcAddress(LoadLibraryA("NTDLL.DLL"), "NtQueryInformationProcess"); + if(NtQueryInformationProcess) { +printf("~1 found NtQueryInformationProcess\n"); fflush(stdout); + if(NtQueryInformationProcess(GetCurrentProcess(), 0, + &pbi, sizeof(pbi), &ulSize) >= 0 && ulSize == sizeof(pbi)) { +printf("~1 NtQueryInformationProcess suceeded\n"); fflush(stdout); + + *(FARPROC *)&AttachConsole = + GetProcAddress(LoadLibraryA("kernel32.dll"), "AttachConsole"); + + if (AttachConsole) { +printf("~1 found AttachConsole\n"); fflush(stdout); + AttachConsole(pbi[5]); +printf("~1 about to freopen CONNOUT\n"); fflush(stdout); + freopen("CONOUT$","wb",stdout); + } else { +printf("~1 failed to find AttachConsole\n"); fflush(stdout); + } + } + } + // AttachConsole(ID ATTACH_PARENT_CONSOLE); // Should work on XP ?? + + /* i mean OpenConsoleW - you are as picky as i am - its + ordinal=519 and it is exported by name; the header(s) + do not include it, which tells me there's got to be a + reason for that. + */ + } +// ~~~~~~~~~~~~~ +#endif // NEVER + +#if defined(TEST_NON_CONSOLE) && defined(NT) +# pragma comment( linker, "/subsystem:windows" ) + +APIENTRY WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow +) { + { /* Only works on >= XP though */ + BOOL (WINAPI *AttachConsole)(DWORD dwProcessId); + + *(FARPROC *)&AttachConsole = + GetProcAddress(LoadLibraryA("kernel32.dll"), "AttachConsole"); + + if (AttachConsole != NULL && AttachConsole(((DWORD)-1))) + { + if (_fileno(stdout) < 0) + freopen("CONOUT$","wb",stdout); + if (_fileno(stderr) < 0) + freopen("CONOUT$","wb",stderr); + if (_fileno(stdin) < 0) + freopen("CONIN$","rb",stdin); +#ifdef __cplusplus + // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well + std::ios::sync_with_stdio(); +#endif + } + } + + return main(__argc, __argv); +} +#endif /* TEST_NON_CONSOLE && NT */ + +int main(int argc, char *argv[]) { + double x[10] = {0.0, 0.5, 0.7, 1.0}; + double y1[10] = {0.0, 0.5, 0.7, 1.0}; + double y2[10] = {0.9, 0.8, 1.4, 1.2}; + double y3[10] = {0.1, 0.8, 0.7, -0.1}; + + double Bx1[10] = {0.0, 0.5, 0.9, 0.5}; + double By1[10] = {0.0, 0.3, 1.2, 0.2}; + double Bx2[10] = {0.1, 0.8, 0.1, 0.2}; + double By2[10] = {0.1, 1.8, 2.0, 0.5}; + + double Bx3[10] = {0.8, 0.4, 1.3, 0.5, 0.23}; + double By3[10] = {0.5, 1.3, 0.4, 0.7, 0.77}; + + plot_col mcols[5] = { + { 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 }, + { 0.0, 0.0, 1.0 }, + { 0.6, 0.6, 0.6 }, + { 1.0, 1.0, 0.0 } }; + + char *ntext[5] = { "A", "B", "C", "D" }; + char *mtext[5] = { "10", "20", "30", "40", "50" }; + + printf("Doing first plot\n"); + if (do_plot(x,y1,y2,y3,4) < 0) + printf("Error - do_plot returned -1!\n"); + + /* Try a second plot */ + printf("Doing second plot\n"); + x[2] = 0.55; + if (do_plot(x,y2,y3,y1,3) < 0) + printf("Error - do_plot returned -1!\n"); + + /* Try vectors */ + printf("Doing vector plot\n"); + if (do_plot_vec(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, 4, 1, Bx3, By3, NULL, NULL, 5)) + printf("Error - do_plot_vec returned -1!\n"); + + printf("Doing vector plot with colors and notation\n"); + if (do_plot_vec(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, 4, 1, Bx3, By3, mcols, mtext, 5)) + printf("Error - do_plot_vec returned -1!\n"); + + printf("Doing vector plot with colors and notation + extra vectors\n"); + if (do_plot_vec2(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, ntext, 4, 1, Bx3, By3, mcols, mtext, 5, + x,y1,y2,y3,mcols,4)) + printf("Error - do_plot_vec returned -1!\n"); + + printf("We're done\n"); + return 0; +} + +#endif /* STANDALONE_TEST */ +/* ---------------------------------------------------------------- */ + diff --git a/plot/plot.h b/plot/plot.h new file mode 100644 index 0000000..89bf16b --- /dev/null +++ b/plot/plot.h @@ -0,0 +1,94 @@ + +#ifndef PLOT_H + +/* + * Simple diagnostic 2d plot function + * + * Copyright 1998 - 2004 Graeme W. Gill + * All rights reserved. + * + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License.txt file for licencing details. + */ + +/* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */ +/* Brown = Y7, Orange = Y8, Grey = Y9, White = Y10 */ + +/* A plot color */ +typedef struct { + float rgb[3]; +} plot_col; + +/* Plot up to 3 X/Y Graphs. return when the user closes the window */ +/* return 0 on success, -1 on error */ +int do_plot(double *x, double *y1, double *y2, double *y3, int n); + +/* Plot up to 3 graphs. */ +/* if dowait > 0, wait for user key */ +/* if dowait < 0, wait for no seconds */ +/* If xmax > xmin, use as x scale, else auto. */ +/* If ymax > ymin, use as y scale, else auto. */ +/* ratio is window X / Y */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int do_plot_x(double *x, double *y1, double *y2, double *y3, int n, +int dowait, double pxmin, double pxmax, double pymin, double pymax, double ratio); + +/* Plot up to 3 graphs + crosses. Wait for key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int do_plot_p(double *x, double *y1, double *y2, double *y3, int n, + double *x4, double *y4, int m); + +/* Public routines */ +/* Plot up to 6 graphs */ +/* return 0 on success, -1 on error */ +/* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */ +int do_plot6(double *x, double *y1, double *y2, double *y3, double *y4, double *y5, double *y6, int n); + +/* Plot up to 6 graphs + optional crosses. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int do_plot6p(double *x, double *y1, double *y2, double *y3, double *y4, double *y5, double *y6, + int n, double *x7, double *y7, int m); + +/* Public routines */ +/* Plot up to 10 graphs */ +/* return 0 on success, -1 on error */ +/* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */ +/* Brown = Y7, Orange = Y8, Grey = Y9, White = Y10 */ +/* if dozero flag, make sure y range covers zero */ +int do_plot10(double *x, double *y1, double *y2, double *y3, double *y4, double *y5, double *y6, + double *y7, double *y8, double *y9, double *y10, + int n, int dozero); + +/* Plot up to 10 graphs + optional crosses. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int do_plot10p(double *x, double *y1, double *y2, double *y3, double *y4, double *y5, double *y6, + double *y7, double *y8, double *y9, double *y10, + int n, double *xp, double *yp, int m); + +/* Plot a bunch of vectors + points + optional colored points & notation */ +/* return 0 on success, -1 on error */ +/* Vectors are x1, y1 to x2, y2 with 'X' at x2, y3, */ +/* Colored annotated Crosss at x3, y3. */ +int do_plot_vec(double xmin, double xmax, double ymin, double ymax, + double *x1, double *y1, double *x2, double *y2, int n, + int dowait, + double *x3, double *y3, plot_col *mcols, char **mtext, int m); + +/* Plot a bunch of vectors + points + optional colored points & notation */ +/* + optional colored vectors */ +/* return 0 on success, -1 on error */ +/* Vectors are x1, y1 to x2, y2 with annotated 'X' at x2, y3, */ +/* Colored annotated Crosss at x3, y3. */ +/* Colored vector from x4, y4 to x5, y5 */ +int do_plot_vec2(double xmin, double xmax, double ymin, double ymax, + double *x1, double *y1, double *x2, double *y2, char **ntext, int n, + int dowait, + double *x3, double *y3, plot_col *mcols, char **mtext, int m, + double *x4, double *y4, double *x5, double *y5, plot_col *ocols, int o); + +#define PLOT_H +#endif /* PLOT_H */ diff --git a/plot/vrml.c b/plot/vrml.c new file mode 100644 index 0000000..5b195c2 --- /dev/null +++ b/plot/vrml.c @@ -0,0 +1,928 @@ + +/* + * Simple diagnostic VRML function library for debugging + * + * Copyright 2005 - 2007 Graeme W. Gill + * All rights reserved. + * + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License.txt file for licencing details. + */ + +#include +#include +#include +#include +#include +#include "numlib.h" +#include "icc.h" +#include "gamut.h" +#include "vrml.h" + +#define MAKE_SOLID + +/* Add a shere at the given location. */ +/* if col[] is NULL, use natural color. */ +/* Need to do this before or after start_line_set()/dd_vertex()/make_lines() ! */ +static void add_marker(vrml *s, double pos[3], double col[3], double rad) { + double rgb[3]; + + if (rad <= 0.0) + rad = 1.0; + + if (col == NULL) { + if (s->isxyz) + s->XYZ2RGB(s, rgb, pos); + else + s->Lab2RGB(s, rgb, pos); + } else { + rgb[0] = col[0]; + rgb[1] = col[1]; + rgb[2] = col[2]; + } + + fprintf(s->fp," # Shere\n"); + fprintf(s->fp," Transform { translation %f %f %f\n", s->scale * pos[1], s->scale * pos[2], s->scale * pos[0] - s->off); + fprintf(s->fp," children [\n"); + fprintf(s->fp," Shape{\n"); + fprintf(s->fp," geometry Sphere { radius %f}\n", s->scale * rad); + fprintf(s->fp," appearance Appearance { material Material "); + fprintf(s->fp,"{ diffuseColor %f %f %f} }\n", rgb[0], rgb[1], rgb[2]); + fprintf(s->fp," }\n"); + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); +} + +/* Add a cone marker to the plot. col == NULL for natural color */ +/* Need to do this before or after start_line_set()/dd_vertex()/make_lines() ! */ +static void add_cone(vrml *s, double pp0[3], double pp1[3], double col[3], double rad) { + double rgb[3]; + double p0[3], p1[3]; + + icmScale3(p0, pp0, s->scale); + icmScale3(p1, pp1, s->scale); + +//printf("~1 cone %f %f %f -> %f %f %f rad %f\n", p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], rad); + + if (rad <= 0.0) + rad = 1.0; + + if (col == NULL) { + icmAdd3(rgb, p1, p0); + icmScale3(rgb, rgb, 0.5); /* Compute half way value */ + if (s->isxyz) + s->XYZ2RGB(s, rgb, rgb); + else + s->Lab2RGB(s, rgb, rgb); + } else { + rgb[0] = col[0]; + rgb[1] = col[1]; + rgb[2] = col[2]; + } + + p0[0] -= s->off; + p1[0] -= s->off; + + { + double base[3] = { 0.0, 0.0, 1.0 }; /* Default orientation of cone is b axis */ + double len; + double loc[3]; + double vec[3]; + double axis[3]; /* Axis to rotate around */ + double rot; /* In radians */ + int j; + +//printf("~1 edge vert %d to %d\n",tp->v[0]->n, tp->v[1]->n); +//printf("~1 edge %f %f %f to %f %f %f\n", +//tp->v[0]->ch[0], tp->v[0]->ch[1], tp->v[0]->ch[2], +//tp->v[1]->ch[0], tp->v[1]->ch[1], tp->v[1]->ch[2]); + + icmAdd3(loc, p1, p0); + icmScale3(loc, loc, 0.5); /* Compute half way value */ + icmSub3(vec, p1, p0); + len = icmNorm3(vec); +//printf("~1 loc = %f %f %f\n", loc[0], loc[1], loc[2]); +//printf("~1 vec = %f %f %f\n", vec[0], vec[1], vec[2]); +//printf("~1 len = %f\n", len); + + if (len < 0.1) + len = 0.1; + + icmNormalize3(base, base, 1.0); + icmNormalize3(vec, vec, 1.0); + icmCross3(axis, base, vec); + rot = icmDot3(base, vec); +//printf("~1 base = %f %f %f\n", base[0], base[1], base[2]); +//printf("~1 vec = %f %f %f\n", vec[0], vec[1], vec[2]); +//printf("~1 axis = %f %f %f, rot = %f\n",axis[0],axis[1],axis[2],rot); + if (icmNorm3sq(axis) < 1e-10) { /* 0 or 180 degrees */ + double base2[3]; + int mxi = 0; +//printf("~1 computing a different axis\n"); + base2[0] = vec[1]; /* Comute vector in a different direction */ + base2[1] = vec[2]; + base2[2] = vec[0]; + for (j = 1; j < 3; j++) { + if (fabs(base2[j]) > fabs(base2[mxi])) + mxi = j; + } + base2[mxi] = -base2[mxi]; + + icmCross3(axis, base2, vec); + if (icmNorm3sq(axis) < 1e-10) { /* 0 or 180 degrees */ + error("VRML rotate axis still too small"); + } + if (rot < 0.0) + rot = 3.1415926; + else + rot = 0.0; + } else { + rot = acos(rot); +//printf("~1 rotation %f\n",rot); + } + + fprintf(s->fp,"\n"); + fprintf(s->fp," # Cone\n"); + fprintf(s->fp," Transform {\n"); + fprintf(s->fp," rotation %f %f %f %f\n",axis[1], axis[2], axis[0], rot); + fprintf(s->fp," translation %f %f %f\n",loc[1], loc[2], loc[0]); + fprintf(s->fp," children [\n"); + fprintf(s->fp," Shape { \n"); + fprintf(s->fp," geometry Cone { bottomRadius %f height %f }\n",s->scale * rad,len); + fprintf(s->fp," appearance Appearance { material Material { diffuseColor %f %f %f } }\n",rgb[0],rgb[1],rgb[2]); + fprintf(s->fp," } \n"); + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); + } +} + +/* Add a text marker to the plot. col == NULL for natural color */ +/* (Need to do this before or after start_line_set()/dd_vertex()/make_lines() !) */ +static void add_text(vrml *s, char *text, double p[3], double col[3], double size) { + double rgb[3]; + + if (size <= 0.0) + size = 1.0; + + if (col == NULL) { + if (s->isxyz) + s->XYZ2RGB(s, rgb, p); + else + s->Lab2RGB(s, rgb, p); + } else { + rgb[0] = col[0]; + rgb[1] = col[1]; + rgb[2] = col[2]; + } + fprintf(s->fp," # Text\n"); + fprintf(s->fp," Transform { translation %f %f %f\n", s->scale * p[1], s->scale * p[2], s->scale * p[0] - s->off); + fprintf(s->fp," children [\n"); + fprintf(s->fp," Shape{\n"); + fprintf(s->fp," geometry Text { string [\"%s\"]\n",text); + fprintf(s->fp," fontStyle FontStyle { family \"SANS\" style \"BOLD\" size %f }\n", + s->scale * size); + fprintf(s->fp," }\n"); + fprintf(s->fp," appearance Appearance { material Material "); + fprintf(s->fp,"{ diffuseColor %f %f %f} }\n", rgb[0], rgb[1], rgb[2]); + fprintf(s->fp," }\n"); + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); +} + +/* Start building up verticies that will be converted to lines */ +/* Set can be from 0 - 9 */ +static void start_line_set(vrml *s, int set) { + if (set < 0 || set > 9) + error("vrml start_line_set set %d out of range",set); + s->set[set].npoints = 0; +} + +/* Add a verticy with color */ +static void add_col_vertex_l(vrml *s, int set, double pos[3], double col[3], int last) { + + if (set < 0 || set > 9) + error("vrml start_line_set set %d out of range",set); + + if (s->set[set].npoints >= s->set[set].paloc) { + s->set[set].paloc = (s->set[set].paloc + 10) * 2; + if (s->set[set].pary == NULL) + s->set[set].pary = malloc(s->set[set].paloc * 6 * (sizeof(double) + sizeof(int))); + else + s->set[set].pary = realloc(s->set[set].pary, s->set[set].paloc * 6 * (sizeof(double) + sizeof(int))); + + if (s->set[set].pary == NULL) + error("VRML malloc failed at count %d\n",s->set[set].paloc); + } + s->set[set].pary[s->set[set].npoints].pp[0] = pos[0]; + s->set[set].pary[s->set[set].npoints].pp[1] = pos[1]; + s->set[set].pary[s->set[set].npoints].pp[2] = pos[2]; + s->set[set].pary[s->set[set].npoints].cc[0] = col[0]; + s->set[set].pary[s->set[set].npoints].cc[1] = col[1]; + s->set[set].pary[s->set[set].npoints].cc[2] = col[2]; + s->set[set].pary[s->set[set].npoints].last = last; + s->set[set].npoints++; +} + +/* Add a verticy with color */ +static void add_col_vertex(vrml *s, int set, double pos[3], double col[3]) { + + add_col_vertex_l(s, set, pos, col, 0); +} + +/* Add a color verticy */ +static void add_vertex(vrml *s, int set, double pos[3]) { + double col[3] = { -1.0, -1.0, -1.0 }; + + add_col_vertex_l(s, set, pos, col, 0); +} + +/* Turn the last added vertex into the last vertex of the line */ +static void make_last_vertex(vrml *s, int set) { + + if (set < 0 || set > 9) + error("vrml start_line_set set %d out of range",set); + + if (s->set[set].npoints <= 0) + warning("vrml plot: tried to set last point with no points added!\n"); + else + s->set[set].pary[s->set[set].npoints-1].last = 1; +} + +/* Convert the verticies to lines, ppset verticies per line (or .last flag) */ +static void make_lines(vrml *s, int set, int ppset) { + int i, j; + + if (set < 0 || set > 9) + error("vrml start_line_set set %d out of range",set); + + fprintf(s->fp,"\n"); + fprintf(s->fp," # Lines\n"); + fprintf(s->fp," Shape {\n"); + fprintf(s->fp," geometry IndexedLineSet { \n"); + fprintf(s->fp," coord Coordinate { \n"); + fprintf(s->fp," point [\n"); + + for (i = 0; i < s->set[set].npoints; i++) { + fprintf(s->fp," %f %f %f,\n", + s->scale * s->set[set].pary[i].pp[1], + s->scale * s->set[set].pary[i].pp[2], + s->scale * s->set[set].pary[i].pp[0] - s->off); + } + + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," coordIndex [\n"); + + for (i = 0; i < s->set[set].npoints;) { + fprintf(s->fp," "); + for (j = 0; i < s->set[set].npoints && j < ppset; j++) { + fprintf(s->fp,"%d, ", i++); + if (s->set[set].pary[i-1].last != 0) + break; + } + fprintf(s->fp,"-1,\n"); + } + fprintf(s->fp," ]\n"); + + /* Color */ + fprintf(s->fp," colorPerVertex TRUE\n"); + fprintf(s->fp," color Color {\n"); + fprintf(s->fp," color [ # RGB colors of each vertex\n"); + + for (i = 0; i < s->set[set].npoints; i++) { + double rgb[3], Lab[3]; + + if (s->set[set].pary[i].cc[0] < 0.0) { + Lab[0] = s->set[set].pary[i].pp[0]; + Lab[1] = s->set[set].pary[i].pp[1]; + Lab[2] = s->set[set].pary[i].pp[2]; + if (s->isxyz) + s->XYZ2RGB(s, rgb, Lab); + else + s->Lab2RGB(s, rgb, Lab); + fprintf(s->fp," %f %f %f,\n", rgb[0], rgb[1], rgb[2]); + } else { + fprintf(s->fp," %f %f %f,\n", s->set[set].pary[i].cc[0], s->set[set].pary[i].cc[1], s->set[set].pary[i].cc[2]); + } + } + fprintf(s->fp," ] \n"); + fprintf(s->fp," }\n"); + /* End color */ + + fprintf(s->fp," }\n"); + fprintf(s->fp," } # end shape\n"); +} + +/* Convert the verticies to triangles */ +static void make_triangles_imp( +vrml *s, +int set, +double trans, /* Transparency level */ +int ixcol, /* NZ for using index color */ +double cc[3] /* Surface color, cc == NULL or cc[0] < 0.0 for natural color */ +) { + int i, nverts, ix; + int v[3]; + + if (set < 0 || set > 9) + error("vrml start_line_set set %d out of range",set); + + fprintf(s->fp," # Triangles\n"); + fprintf(s->fp," Transform {\n"); + fprintf(s->fp," translation 0 0 0\n"); + fprintf(s->fp," children [\n"); + fprintf(s->fp," Shape { \n"); + fprintf(s->fp," geometry IndexedFaceSet {\n"); +// fprintf(s->fp," ccw FALSE\n"); + fprintf(s->fp," convex TRUE\n"); +#ifdef MAKE_SOLID + fprintf(s->fp," solid FALSE\n"); /* If we want them visible from both sides */ +#endif + fprintf(s->fp,"\n"); + fprintf(s->fp," coord Coordinate { \n"); + fprintf(s->fp," point [ # Verticy coordinates\n"); + + /* Spit out the point values, in order. */ + /* Note that a->x, b->y, L->z */ + for (i = 0; i < s->set[set].npoints; i++) { + fprintf(s->fp," %f %f %f,\n", + s->scale * s->set[set].pary[i].pp[1], + s->scale * s->set[set].pary[i].pp[2], + s->scale * s->set[set].pary[i].pp[0] - s->off); + } + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp,"\n"); + fprintf(s->fp," coordIndex [ # Indexes of poligon Verticies \n"); + + for (i = 0; i < s->ntris; i++) { + if (s->tary[i].set == set) + fprintf(s->fp," %d, %d, %d, -1\n", s->tary[i].ix[0], s->tary[i].ix[1], s->tary[i].ix[2]); + } + + fprintf(s->fp," ]\n"); + fprintf(s->fp,"\n"); + fprintf(s->fp," colorPerVertex TRUE\n"); + fprintf(s->fp," color Color {\n"); + fprintf(s->fp," color [ # RGB colors of each vertex\n"); + + /* Spit out the colors for each vertex */ + for (i = 0; i < s->set[set].npoints; i++) { + double out[3]; + double rgb[3]; + + if (ixcol) { + fprintf(s->fp," %f %f %f,\n",s->set[set].pary[i].cc[0], s->set[set].pary[i].cc[1], s->set[set].pary[i].cc[2]); + } else { + if (cc == NULL || cc[0] < 0.0) { + if (s->isxyz) + s->XYZ2RGB(s, rgb, s->set[set].pary[i].pp); + else + s->Lab2RGB(s, rgb, s->set[set].pary[i].pp); + fprintf(s->fp," %f %f %f,\n", rgb[0], rgb[1], rgb[2]); + } else { + fprintf(s->fp," %f %f %f,\n", cc[0], cc[1], cc[2]); + } + } + } + fprintf(s->fp," ] \n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," appearance Appearance { \n"); + fprintf(s->fp," material Material {\n"); + fprintf(s->fp," transparency %f\n",trans); + fprintf(s->fp," ambientIntensity 0.3\n"); + fprintf(s->fp," shininess 0.5\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," } # end Shape\n"); + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); +} + +/* Convert the verticies to triangles with vertex color */ +static void make_triangles_vc( +vrml *s, +int set, +double trans /* Transparency level */ +) { + make_triangles_imp(s, set, trans, 1, NULL); +} + +/* Convert the verticies to triangles with color */ +static void make_triangles( +vrml *s, +int set, +double trans, /* Transparency level */ +double cc[3] /* Surface color, cc == NULL or cc[0] < 0.0 for natural color */ +) { + make_triangles_imp(s, set, trans, 0, cc); +} + +/* Add a triangle */ +static void add_triangle(vrml *s, int set, int ix[3]) { + + if (set < 0 || set > 9) + error("vrml start_line_set set %d out of range",set); + + if (s->ntris >= s->taloc) { + s->taloc = (s->taloc + 10) * 2; + if (s->tary == NULL) + s->tary = malloc(s->taloc * 4 * sizeof(int)); + else + s->tary = realloc(s->tary, s->taloc * 4 * sizeof(int)); + + if (s->tary == NULL) + error("VRML malloc failed at count %d\n",s->taloc); + } + s->tary[s->ntris].set = set; + s->tary[s->ntris].ix[0] = ix[0]; + s->tary[s->ntris].ix[1] = ix[1]; + s->tary[s->ntris].ix[2] = ix[2]; + s->ntris++; +} + +/* Create a gamut surface solid or wireframe from the given gamut. */ +/* Use the given transparency level. */ +/* Display in natural colors if c[0] < 0.0, */ +/* or the given color otherwise */ +static void make_gamut_surface_2( +vrml *s, +gamut *g, +double trans, /* Transparency level */ +int wire, /* Z for solid, NZ for wireframe */ +double cc[3] /* Surface color, cc[0] < 0.0 for natural color */ +) { + int i, nverts, ix; + int v[3]; + + nverts = g->nverts(g); + + if (nverts == 0) + return; + + fprintf(s->fp," # Gamut surface\n"); + fprintf(s->fp," Transform {\n"); + fprintf(s->fp," translation 0 0 0\n"); + fprintf(s->fp," children [\n"); + fprintf(s->fp," Shape { \n"); + if (wire) { + fprintf(s->fp," geometry IndexedLineSet {\n"); + } else { + fprintf(s->fp," geometry IndexedFaceSet {\n"); +// fprintf(s->fp," ccw FALSE\n"); + fprintf(s->fp," convex TRUE\n"); +#ifdef MAKE_SOLID + fprintf(s->fp," solid FALSE\n"); /* If we want them visible from both sides */ +#endif + } + fprintf(s->fp,"\n"); + fprintf(s->fp," coord Coordinate { \n"); + fprintf(s->fp," point [ # Verticy coordinates\n"); + + /* Spit out the point values, in order. */ + /* Note that a->x, b->y, L->z */ + for (ix = i = 0; ix >= 0 && i < nverts; i++) { + double out[3]; + + ix = g->getvert(g, NULL, out, ix); + fprintf(s->fp," %f %f %f,\n",s->scale * out[1], s->scale * out[2], s->scale * out[0] - s->off); + } + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp,"\n"); + fprintf(s->fp," coordIndex [ # Indexes of poligon Verticies \n"); + + g->startnexttri(g); + while (g->getnexttri(g, v) == 0) { + if (wire) { + if (v[0] < v[1]) /* Only output 1 wire of two on an edge */ + fprintf(s->fp," %d, %d, -1\n", v[0], v[1]); + if (v[1] < v[2]) + fprintf(s->fp," %d, %d, -1\n", v[1], v[2]); + if (v[2] < v[0]) + fprintf(s->fp," %d, %d, -1\n", v[2], v[0]); + } else { + fprintf(s->fp," %d, %d, %d, -1\n", v[0], v[1], v[2]); + } + } + fprintf(s->fp," ]\n"); + fprintf(s->fp,"\n"); + fprintf(s->fp," colorPerVertex TRUE\n"); + fprintf(s->fp," color Color {\n"); + fprintf(s->fp," color [ # RGB colors of each vertex\n"); + + /* Spit out the colors for each vertex */ + for (ix = i = 0; ix >= 0 && i < nverts; i++) { + double out[3]; + double rgb[3]; + + ix = g->getvert(g, NULL, out, ix); + + if (cc == NULL || cc[0] < 0.0) { + if (s->isxyz) + s->XYZ2RGB(s, rgb, out); + else + s->Lab2RGB(s, rgb, out); + fprintf(s->fp," %f %f %f,\n", rgb[0], rgb[1], rgb[2]); + } else { + fprintf(s->fp," %f %f %f,\n", cc[0], cc[1], cc[2]); + } + } + fprintf(s->fp," ] \n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," appearance Appearance { \n"); + fprintf(s->fp," material Material {\n"); + fprintf(s->fp," transparency %f\n",trans); + fprintf(s->fp," ambientIntensity 0.3\n"); + fprintf(s->fp," shininess 0.5\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," } # end Shape\n"); + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); +} + +/* Create a gamut surface from the given gamut. */ +/* Use the given transparency level. */ +/* Display in natural colors if c[0] < 0.0, */ +/* or the given color otherwise */ +static void make_gamut_surface( +vrml *s, +gamut *g, +double trans, /* Transparency level */ +double cc[3] /* Surface color, cc[0] < 0.0 for natural color */ +) { + s->make_gamut_surface_2(s, g, trans, 0, cc); +} + +/* Add cusp markers from a gamut surface */ +/* Use the given transparency level. */ +/* Display in natural colors if c[0] < 0.0, */ +/* or the given color otherwise */ +static void add_cusps( +vrml *s, +gamut *g, +double trans, /* Transparency level */ +double cc[3] /* Surface color, cc[0] < 0.0 for natural color, NULL for default */ +) { + double cusps[6][3]; + double ccolors[6][3] = { + { 1.0, 0.1, 0.1 }, /* Red */ + { 1.0, 1.0, 0.1 }, /* Yellow */ + { 0.1, 1.0, 0.1 }, /* Green */ + { 0.1, 1.0, 1.0 }, /* Cyan */ + { 0.1, 0.1, 1.0 }, /* Blue */ + { 1.0, 0.1, 1.0 } /* Magenta */ + }; + double rgb[3]; + double *cv = NULL; + int i; + int v[3]; + + if (g->getcusps(g, cusps) != 0) + return; + + fprintf(s->fp," # Cusps\n"); + for (i = 0; i < 6; i++) { + if (cc == NULL) { + cv = ccolors[i]; + } else if (cc[0] < 0.0) { + if (s->isxyz) + s->XYZ2RGB(s, rgb, cusps[i]); + else + s->Lab2RGB(s, rgb, cusps[i]); + cv = rgb; + } else { + cv = cc; + } + fprintf(s->fp,"\n"); + fprintf(s->fp," Transform {\n"); + fprintf(s->fp," translation %f %f %f\n",s->scale * cusps[i][1], s->scale * cusps[i][2], s->scale * cusps[i][0] - s->off); + fprintf(s->fp," children [\n"); + fprintf(s->fp," Shape { \n"); + fprintf(s->fp," geometry Sphere { radius 2.0 }\n"); + fprintf(s->fp," appearance Appearance { \n"); + fprintf(s->fp," material Material {\n"); + fprintf(s->fp," transparency %f\n",trans); + fprintf(s->fp," ambientIntensity 0.3\n"); + fprintf(s->fp," shininess 0.5\n"); + fprintf(s->fp," diffuseColor %f %f %f\n", cv[0],cv[1],cv[2]); + fprintf(s->fp," }\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," } \n"); + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); + } +} + +/* Clear verticies and triangles */ +static void clear(vrml *s) { + int i; + + for (i = 0; i < 10; i++) { + if (s->set[i].pary != NULL) + free(s->set[i].pary); + s->set[i].pary = NULL; + s->set[i].npoints = s->set[i].paloc = 0; + } + if (s->tary != NULL) + free(s->tary); + s->tary = NULL; + s->ntris = s->taloc = 0; +} + +/* Helper :- convert a Lab value to RGB for display purposes */ +static void Lab2RGB(vrml *s, double *out, double *in) { + double L = in[0], a = in[1], b = in[2]; + double x,y,z,fx,fy,fz; + double R, G, B; + + /* Scale so that black is visible */ + L = L * (100 - 40.0)/100.0 + 40.0; + + /* First convert to XYZ using D50 white point */ + if (L > 8.0) { + fy = (L + 16.0)/116.0; + y = pow(fy,3.0); + } else { + y = L/903.2963058; + fy = 7.787036979 * y + 16.0/116.0; + } + + fx = a/500.0 + fy; + if (fx > 24.0/116.0) + x = pow(fx,3.0); + else + x = (fx - 16.0/116.0)/7.787036979; + + fz = fy - b/200.0; + if (fz > 24.0/116.0) + z = pow(fz,3.0); + else + z = (fz - 16.0/116.0)/7.787036979; + + x *= 0.9642; /* Multiply by white point, D50 */ + y *= 1.0; + z *= 0.8249; + + /* Now convert to sRGB values */ + R = x * 3.2410 + y * -1.5374 + z * -0.4986; + G = x * -0.9692 + y * 1.8760 + z * 0.0416; + B = x * 0.0556 + y * -0.2040 + z * 1.0570; + + if (R < 0.0) + R = 0.0; + else if (R > 1.0) + R = 1.0; + + if (G < 0.0) + G = 0.0; + else if (G > 1.0) + G = 1.0; + + if (B < 0.0) + B = 0.0; + else if (B > 1.0) + B = 1.0; + + R = pow(R, 1.0/2.2); + G = pow(G, 1.0/2.2); + B = pow(B, 1.0/2.2); + + /* For a black background: */ +// R = R * 0.85 + 0.15; +// G = G * 0.85 + 0.15; +// B = B * 0.85 + 0.15; + + /* For a white background: */ + R = R * 0.70 + 0.05; + G = G * 0.70 + 0.05; + B = B * 0.70 + 0.05; + + out[0] = R; + out[1] = G; + out[2] = B; +} + +/* Helper :- convert an XYZ value to RGB for display purposes */ +static void XYZ2RGB(vrml *s, double *out, double *in) { + double x = in[0], y = in[1], z = in[2]; + double R, G, B; + + /* Now convert to sRGB values */ + R = x * 3.2410 + y * -1.5374 + z * -0.4986; + G = x * -0.9692 + y * 1.8760 + z * 0.0416; + B = x * 0.0556 + y * -0.2040 + z * 1.0570; + + if (R < 0.0) + R = 0.0; + else if (R > 1.0) + R = 1.0; + + if (G < 0.0) + G = 0.0; + else if (G > 1.0) + G = 1.0; + + if (B < 0.0) + B = 0.0; + else if (B > 1.0) + B = 1.0; + + R = pow(R, 1.0/2.2); + G = pow(G, 1.0/2.2); + B = pow(B, 1.0/2.2); + + /* For a black background: */ +// R = R * 0.85 + 0.15; +// G = G * 0.85 + 0.15; +// B = B * 0.85 + 0.15; + + /* For a white background: */ + R = R * 0.70 + 0.05; + G = G * 0.70 + 0.05; + B = B * 0.70 + 0.05; + + out[0] = R; + out[1] = G; + out[2] = B; +} + +static void del_vrml(vrml *s); + +/* Constructor */ +vrml *new_vrml( +char *name, +int doaxes, +int isxyz +) { + vrml *s; + + int i, j; + + if ((s = (vrml *)calloc(1, sizeof(vrml))) == NULL) { + warning("Malloc of vrml plot object failed"); + return NULL; + } + + s->del = del_vrml; + s->add_marker = add_marker; + s->add_cone = add_cone; + s->add_text = add_text; + s->start_line_set = start_line_set; + s->add_vertex = add_vertex; + s->add_col_vertex = add_col_vertex; + s->make_last_vertex = make_last_vertex; + s->add_triangle = add_triangle; + s->make_lines = make_lines; + s->make_triangles = make_triangles; + s->make_triangles_vc = make_triangles_vc; + s->make_gamut_surface = make_gamut_surface; + s->make_gamut_surface_2 = make_gamut_surface_2; + s->add_cusps = add_cusps; + s->clear = clear; + s->Lab2RGB = Lab2RGB; + s->XYZ2RGB = XYZ2RGB; + + s->isxyz = isxyz; + + if (s->isxyz) { + s->scale = 100.0; + s->off = 50.0; + } else { + s->scale = 1.0; + s->off = 50.0; + } + + if ((s->fp = fopen(name,"w")) == NULL) { + warning("Opening of vrml plot file '%s' for write failed",name); + free(s); + return NULL; + } + + fprintf(s->fp,"#VRML V2.0 utf8\n"); + fprintf(s->fp,"\n"); + fprintf(s->fp,"# Created by the Argyll CMS\n"); + fprintf(s->fp,"Transform {\n"); + fprintf(s->fp," children [\n"); + fprintf(s->fp,"\n"); + fprintf(s->fp," NavigationInfo {\n"); + fprintf(s->fp," type \"EXAMINE\" # It's an object we examine\n"); + fprintf(s->fp," } # We'll add our own light\n"); + fprintf(s->fp,"\n"); + fprintf(s->fp," DirectionalLight {\n"); + fprintf(s->fp," direction 0 0 -1 # Light illuminating the scene\n"); + fprintf(s->fp," direction 0 -1 0 # Light illuminating the scene\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp,"\n"); + fprintf(s->fp," Viewpoint {\n"); + fprintf(s->fp," position 0 0 340 # Position we view from\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp,"\n"); + if (doaxes != 0) { + /* Axes definition */ + struct { + char *label; + double x, y, z; /* == a,b,L or Y,Z,X */ + double wx, wy, wz; + double r, g, b; + } axes[2][6] = { + { /* Box coords are center and size: */ + { "L", 0, 0, 50, 2, 2, 100, .7, .7, .7 }, /* L axis */ + { "+a", 50, 0, 0, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */ + { "-b", 0, -50, 0, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */ + { "-a", -50, 0, 0, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */ + { "+b", 0, 50, 0, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */ + { NULL }, + }, { + { "X", 0, 0, 50, 2, 2, 100, .7, .7, .7 }, /* X axis */ + { "Y", 50, 0, 0, 100, 2, 2, 1, 0, 0 }, /* Y (red) axis */ + { "Z", 0, 50, 0, 2, 100, 2, 0, 0, 1 }, /* Z (blue) axis */ + { NULL }, + } + }; + + if (s->isxyz) { + j = 1; + fprintf(s->fp," # XYZ axes as boxes:\n"); + } else { + j = 0; + fprintf(s->fp," # Lab axes as boxes:\n"); + } + for (i = 0; ; i++) { + double toff[3] = { -3.0, -2.0, 0 }; + + if (axes[j][i].label == NULL) + break; + + fprintf(s->fp," Transform { translation %f %f %f\n", axes[j][i].x, axes[j][i].y, axes[j][i].z - s->off); + fprintf(s->fp," children [\n"); + fprintf(s->fp," Shape {\n"); + fprintf(s->fp," geometry Box { size %f %f %f }\n", + axes[j][i].wx, axes[j][i].wy, axes[j][i].wz); + fprintf(s->fp," appearance Appearance {"); + fprintf(s->fp," material Material { diffuseColor %f %f %f }\n", axes[j][i].r, axes[0][i].g, axes[0][i].b); + fprintf(s->fp," }\n"); + fprintf(s->fp," }\n"); + fprintf(s->fp," ]\n"); + fprintf(s->fp," }\n"); + + if (fabs(axes[j][i].x) > fabs(axes[j][i].y) && fabs(axes[j][i].x) > fabs(axes[j][i].z)) { + if (axes[j][i].x > 0.0) + toff[0] += axes[j][i].x + 0.5 * axes[j][i].wx + 5.0; + else + toff[0] += axes[j][i].x - 0.5 * axes[j][i].wx - 5.0; + } else if (fabs(axes[j][i].y) > fabs(axes[j][i].x) && fabs(axes[j][i].y) > fabs(axes[j][i].z)) { + if (axes[j][i].y > 0.0) + toff[1] += axes[j][i].y + 0.5 * axes[j][i].wy + 5.0; + else + toff[1] += axes[j][i].y - 0.5 * axes[j][i].wy - 5.0; + } else { + if (axes[j][i].z > 0.0) + toff[2] += axes[j][i].z + 0.5 * axes[j][i].wz + 5.0; + else + toff[2] += axes[j][i].z - 0.5 * axes[j][i].wz - 5.0; + } + + fprintf(s->fp,"Transform { translation %f %f %f\n", toff[0], toff[1], toff[2] - s->off); + fprintf(s->fp,"\tchildren [\n"); + fprintf(s->fp,"\t\tShape {\n"); + fprintf(s->fp,"\t\t\tgeometry Text { string [\"%s\"]\n",axes[j][i].label); + fprintf(s->fp,"\t\t\t\tfontStyle FontStyle { family \"SANS\" style \"BOLD\" size %f }\n", + 10.0); + fprintf(s->fp,"\t\t\t\t}\n"); + fprintf(s->fp,"\t\t\tappearance Appearance { material Material "); + fprintf(s->fp,"{ diffuseColor %f %f %f} }\n", axes[j][i].r, axes[j][i].g, axes[j][i].b); + fprintf(s->fp,"\t\t}\n"); + fprintf(s->fp,"\t]\n"); + fprintf(s->fp,"}\n"); + } + fprintf(s->fp,"\n"); + } + + return s; +} + +/* Finish writing the file and free ourselves */ +static void del_vrml(vrml *s) { + int i; + + fprintf(s->fp,"\n"); + fprintf(s->fp," ] # end of children for world\n"); + fprintf(s->fp,"}\n"); + + fflush(s->fp); + if (fclose(s->fp) != 0) + error("VRML: Error closing VRML file\n"); + + for (i = 0; i < 10; i++) { + if (s->set[i].pary) + free(s->set[i].pary); + } + if (s->tary) + free(s->tary); + free(s); +} + diff --git a/plot/vrml.h b/plot/vrml.h new file mode 100644 index 0000000..e3991c5 --- /dev/null +++ b/plot/vrml.h @@ -0,0 +1,113 @@ + +#ifndef VRML_H + +/* + * Simple diagnostic VRML function library for debugging + * + * Copyright 2005 - 2007 Graeme W. Gill + * All rights reserved. + * + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License.txt file for licencing details. + */ + +struct _vrml { + +/* Private: */ + FILE *fp; + + int isxyz; /* nz if XYZ plot, (range 0..1) */ + double scale; /* Scale factor to use (applied before off) */ + double off; /* Gamut L center, usually 50, to put 50 at center of view */ + + /* Expandable point arrays */ + struct { + int npoints; + int paloc; + struct { + double pp[3]; /* Vertex position */ + double cc[3]; /* Vertex color */ + int last; /* Last vertex of line flag */ + } *pary; + } set[10]; /* Ten sets */ + + /* Expandable triangle vertex index */ + int ntris; + int taloc; + struct { int set; int ix[3]; } *tary; + +/* Public: */ + + /* Methods */ + + /* Finish writing the file and free ourselves */ + void (*del)(struct _vrml *s); + + /* Add a spherical marker point to the plot. col == NULL for natural color */ + /* (Need to do this before or after start_line_set()/dd_vertex()/make_lines() !) */ + void (*add_marker)(struct _vrml *s, double pos[3], double col[3], double rad); + + /* Add a cone marker to the plot. col == NULL for natural color */ + /* (Need to do this before or after start_line_set()/dd_vertex()/make_lines() !) */ + void (*add_cone)(struct _vrml *s, double p0[3], double p1[3], double col[3], double rad); + + /* Add a text marker to the plot. col == NULL for natural color */ + /* (Need to do this before or after start_line_set()/dd_vertex()/make_lines() !) */ + void (*add_text)(struct _vrml *s, char *text, double p[3], double col[3], double size); + + + /* Start building up verticies that will be converted to lines */ + /* Set can be from 0 - 9 */ + void (*start_line_set)(struct _vrml *s, int set); + + /* Add a verticy (color automatic from Lab position) */ + void (*add_vertex)(struct _vrml *s, int set, double pos[3]); + + /* Add a verticy with color */ + void (*add_col_vertex)(struct _vrml *s, int set, double pos[3], double col[3]); + + /* Turn the last added vertex into the last vertex of the line */ + void (*make_last_vertex)(struct _vrml *s, int set); + + /* Convert the verticies to lines, ppset verticies per line (or using .last flag) */ + /* Use large ppset for just .last flag */ + void (*make_lines)(struct _vrml *s, int set, int ppset); + + /* Add a triangles vertexes defined by vertex index */ + void (*add_triangle)(struct _vrml *s, int set, int ix[3]); + + /* Convert the triangle vertexes to triangles with overall color */ + void (*make_triangles)(struct _vrml *s, int set, double trans, double col[3]); + + /* Convert the triangle vertexes to triangles using vertex colors */ + void (*make_triangles_vc)(struct _vrml *s, int set, double trans); + + /* Clear verticies and triangles */ + void (*clear)(struct _vrml *s); + + /* Helper :- convert a Lab value to RGB */ + void (*Lab2RGB)(struct _vrml *s, double *out, double *in); + + /* Helper :- convert a XYZ value to RGB */ + void (*XYZ2RGB)(struct _vrml *s, double *out, double *in); + +#ifdef GAMUT_H /* If gamut.h is #included ahead of us */ + /* Create a solid gamut surface from the given gamut */ + /* trans is trasparency, cc is surface color, cc[0] < 0.0 for natural */ + void (*make_gamut_surface)(struct _vrml *s, gamut *g, double trans, double cc[3]); + + /* Create a solid or wireframe gamut surface from the given gamut */ + /* trans is trasparency, cc is surface color, cc[0] < 0.0 for natural */ + void (*make_gamut_surface_2)(struct _vrml *s, gamut *g, double trans, int wire, double cc[3]); + + /* Add cusp markers from the gamut surface */ + void (*add_cusps)(struct _vrml *s, gamut *g, double trans, double cc[3]); +#endif /* GAMUT_H */ + +}; typedef struct _vrml vrml; + +/* Constructor. */ +vrml *new_vrml(char *name, int doaxes, int isxyz); + +#define VRML_H +#endif /* VRML_H */ -- cgit v1.2.3