summaryrefslogtreecommitdiff
path: root/plot
diff options
context:
space:
mode:
Diffstat (limited to 'plot')
-rw-r--r--plot/Imakefile6
-rw-r--r--plot/Jamfile27
-rw-r--r--plot/License.txt662
-rw-r--r--plot/Makefile.am12
-rw-r--r--plot/Readme.txt2
-rw-r--r--plot/afiles14
-rw-r--r--plot/osx/Jamfile21
-rw-r--r--plot/osx/Readme.txt1
-rw-r--r--plot/osx/acoccoa.h402
-rw-r--r--plot/osx/helloc.c313
-rw-r--r--plot/osx/hellom.m181
-rw-r--r--plot/plot.c2511
-rw-r--r--plot/plot.h94
-rw-r--r--plot/vrml.c928
-rw-r--r--plot/vrml.h113
15 files changed, 5287 insertions, 0 deletions
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. <http://fsf.org/>
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+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
+<http://www.gnu.org/licenses/>.
+
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 <Carbon/Carbon.h>
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
+# include <objc/runtime.h>
+# include <objc/message.h>
+#else
+# include <objc/objc-runtime.h>
+
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __OBJC__
+# include <Foundation/Foundation.h>
+# include <AppKit/AppKit.h>
+#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 <Foundation/Foundation.h>
+#include <AppKit/AppKit.h>
+
+#include <objc/objc-runtime.h> /* 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#include <math.h>
+#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 <windows.h>
+
+#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 <Foundation/Foundation.h>
+#include <AppKit/AppKit.h>
+
+#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 <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#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 <windows.h>
+//#include <stdio.h>
+#include <fcntl.h>
+//#include <io.h>
+
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#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 */