summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--LICENSE552
-rw-r--r--doc/intro.md3
-rw-r--r--project.clj8
-rw-r--r--src/dactyl_cave/alternathumb.clj149
-rw-r--r--src/dactyl_cave/cave.clj337
-rw-r--r--src/dactyl_cave/core.clj6
-rw-r--r--src/dactyl_cave/key.clj81
-rw-r--r--src/dactyl_cave/text.clj134
-rw-r--r--src/dactyl_cave/thumb.clj173
-rw-r--r--src/scad_demo/core.clj11
-rw-r--r--target/classes/META-INF/maven/dactyl-cave/dactyl-cave/pom.properties6
-rw-r--r--target/repl-port1
-rw-r--r--target/stale/extract-native.dependencies1
-rw-r--r--test/dactyl_cave/core_test.clj7
15 files changed, 1132 insertions, 339 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..74c36c8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*~
+\#*\#
diff --git a/LICENSE b/LICENSE
index d6a9326..786edf6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,340 +1,214 @@
-GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- 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
-this service 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.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-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
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the 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 a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE 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.
-
- 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
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- {description}
- Copyright (C) {year} {fullname}
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- {signature of Ty Coon}, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
+CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and
+documentation distributed under this Agreement, and
+
+b) in the case of each subsequent Contributor:
+
+i) changes to the Program, and
+
+ii) additions to the Program;
+
+where such changes and/or additions to the Program originate from and are
+distributed by that particular Contributor. A Contribution 'originates' from
+a Contributor if it was added to the Program by such Contributor itself or
+anyone acting on such Contributor's behalf. Contributions do not include
+additions to the Program which: (i) are separate modules of software
+distributed in conjunction with the Program under their own license
+agreement, and (ii) are not derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which are
+necessarily infringed by the use or sale of its Contribution alone or when
+combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement,
+including all Contributors.
+
+2. GRANT OF RIGHTS
+
+a) Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide, royalty-free copyright license to
+reproduce, prepare derivative works of, publicly display, publicly perform,
+distribute and sublicense the Contribution of such Contributor, if any, and
+such derivative works, in source code and object code form.
+
+b) Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide, royalty-free patent license under
+Licensed Patents to make, use, sell, offer to sell, import and otherwise
+transfer the Contribution of such Contributor, if any, in source code and
+object code form. This patent license shall apply to the combination of the
+Contribution and the Program if, at the time the Contribution is added by the
+Contributor, such addition of the Contribution causes such combination to be
+covered by the Licensed Patents. The patent license shall not apply to any
+other combinations which include the Contribution. No hardware per se is
+licensed hereunder.
+
+c) Recipient understands that although each Contributor grants the licenses
+to its Contributions set forth herein, no assurances are provided by any
+Contributor that the Program does not infringe the patent or other
+intellectual property rights of any other entity. Each Contributor disclaims
+any liability to Recipient for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a condition to
+exercising the rights and licenses granted hereunder, each Recipient hereby
+assumes sole responsibility to secure any other intellectual property rights
+needed, if any. For example, if a third party patent license is required to
+allow Recipient to distribute the Program, it is Recipient's responsibility
+to acquire that license before distributing the Program.
+
+d) Each Contributor represents that to its knowledge it has sufficient
+copyright rights in its Contribution, if any, to grant the copyright license
+set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under
+its own license agreement, provided that:
+
+a) it complies with the terms and conditions of this Agreement; and
+
+b) its license agreement:
+
+i) effectively disclaims on behalf of all Contributors all warranties and
+conditions, express and implied, including warranties or conditions of title
+and non-infringement, and implied warranties or conditions of merchantability
+and fitness for a particular purpose;
+
+ii) effectively excludes on behalf of all Contributors all liability for
+damages, including direct, indirect, special, incidental and consequential
+damages, such as lost profits;
+
+iii) states that any provisions which differ from this Agreement are offered
+by that Contributor alone and not by any other party; and
+
+iv) states that source code for the Program is available from such
+Contributor, and informs licensees how to obtain it in a reasonable manner on
+or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+a) it must be made available under this Agreement; and
+
+b) a copy of this Agreement must be included with each copy of the Program.
+
+Contributors may not remove or alter any copyright notices contained within
+the Program.
+
+Each Contributor must identify itself as the originator of its Contribution,
+if any, in a manner that reasonably allows subsequent Recipients to identify
+the originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with
+respect to end users, business partners and the like. While this license is
+intended to facilitate the commercial use of the Program, the Contributor who
+includes the Program in a commercial product offering should do so in a
+manner which does not create potential liability for other Contributors.
+Therefore, if a Contributor includes the Program in a commercial product
+offering, such Contributor ("Commercial Contributor") hereby agrees to defend
+and indemnify every other Contributor ("Indemnified Contributor") against any
+losses, damages and costs (collectively "Losses") arising from claims,
+lawsuits and other legal actions brought by a third party against the
+Indemnified Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program in
+a commercial product offering. The obligations in this section do not apply
+to any claims or Losses relating to any actual or alleged intellectual
+property infringement. In order to qualify, an Indemnified Contributor must:
+a) promptly notify the Commercial Contributor in writing of such claim, and
+b) allow the Commercial Contributor tocontrol, and cooperate with the
+Commercial Contributor in, the defense and any related settlement
+negotiations. The Indemnified Contributor may participate in any such claim
+at its own expense.
+
+For example, a Contributor might include the Program in a commercial product
+offering, Product X. That Contributor is then a Commercial Contributor. If
+that Commercial Contributor then makes performance claims, or offers
+warranties related to Product X, those performance claims and warranties are
+such Commercial Contributor's responsibility alone. Under this section, the
+Commercial Contributor would have to defend claims against the other
+Contributors related to those performance claims and warranties, and if a
+court requires any other Contributor to pay any damages as a result, the
+Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON
+AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
+EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR
+CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
+PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the
+appropriateness of using and distributing the Program and assumes all risks
+associated with its exercise of rights under this Agreement , including but
+not limited to the risks and costs of program errors, compliance with
+applicable laws, damage to or loss of data, programs or equipment, and
+unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
+LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of the
+remainder of the terms of this Agreement, and without further action by the
+parties hereto, such provision shall be reformed to the minimum extent
+necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program itself
+(excluding combinations of the Program with other software or hardware)
+infringes such Recipient's patent(s), then such Recipient's rights granted
+under Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to
+comply with any of the material terms or conditions of this Agreement and
+does not cure such failure in a reasonable period of time after becoming
+aware of such noncompliance. If all Recipient's rights under this Agreement
+terminate, Recipient agrees to cease use and distribution of the Program as
+soon as reasonably practicable. However, Recipient's obligations under this
+Agreement and any licenses granted by Recipient relating to the Program shall
+continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in
+order to avoid inconsistency the Agreement is copyrighted and may only be
+modified in the following manner. The Agreement Steward reserves the right to
+publish new versions (including revisions) of this Agreement from time to
+time. No one other than the Agreement Steward has the right to modify this
+Agreement. The Eclipse Foundation is the initial Agreement Steward. The
+Eclipse Foundation may assign the responsibility to serve as the Agreement
+Steward to a suitable separate entity. Each new version of the Agreement will
+be given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program
+(including its Contributions) under the new version. Except as expressly
+stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
+licenses to the intellectual property of any Contributor under this
+Agreement, whether expressly, by implication, estoppel or otherwise. All
+rights in the Program not expressly granted under this Agreement are
+reserved.
+
+This Agreement is governed by the laws of the State of Washington and the
+intellectual property laws of the United States of America. No party to this
+Agreement will bring a legal action under this Agreement more than one year
+after the cause of action arose. Each party waives its rights to a jury trial
+in any resulting litigation.
diff --git a/doc/intro.md b/doc/intro.md
new file mode 100644
index 0000000..cfdc90a
--- /dev/null
+++ b/doc/intro.md
@@ -0,0 +1,3 @@
+# Introduction to dactyl-cave
+
+TODO: write [great documentation](http://jacobian.org/writing/great-documentation/what-to-write/)
diff --git a/project.clj b/project.clj
new file mode 100644
index 0000000..60f7b85
--- /dev/null
+++ b/project.clj
@@ -0,0 +1,8 @@
+(defproject dactyl-cave "0.1.0-SNAPSHOT"
+ :description "FIXME: write description"
+ :url "http://example.com/FIXME"
+ :license {:name "Eclipse Public License"
+ :url "http://www.eclipse.org/legal/epl-v10.html"}
+ :dependencies [[org.clojure/clojure "1.5.1"]
+ [unicode-math "0.2.0"]
+ [scad-clj "0.1.0"]])
diff --git a/src/dactyl_cave/alternathumb.clj b/src/dactyl_cave/alternathumb.clj
new file mode 100644
index 0000000..ddfb42a
--- /dev/null
+++ b/src/dactyl_cave/alternathumb.clj
@@ -0,0 +1,149 @@
+(ns dactyl-cave.alternathumb
+ (:use [scad-clj.scad])
+ (:use [scad-clj.model])
+ (:use [unicode-math.core])
+ (:require [dactyl-cave.key :as key])
+ (:require [dactyl-cave.cave :as cave]))
+
+(defn- scoop [angle radius [x y :as direction] shape]
+ (->> shape
+ (translate [0 0 radius])))
+
+(defn thumb-x+x-column [shape]
+ (let [α (/ π 12)
+ radius (/ (/ key/pillar-depth 2)
+ (Math/sin (/ α 2)))
+ spin-shape (->> shape
+ (translate [0 0 (+ (- key/full-height)
+ (- radius))]))]
+ (translate
+ [0 0 (+ radius key/full-height)]
+ (union
+ spin-shape
+
+ (->> spin-shape
+ (rotate (- α) [1 0 0]))))))
+
+(defn thumb-2x-column [shape]
+ (let [α (/ π 12)
+ radius (/ (/ key/pillar-depth 2)
+ (Math/sin (/ α 2)))
+ spin-shape (->> shape
+ (translate [0 0 (+ (- key/full-height)
+ (- radius))]))]
+ (translate
+ [0 0 (+ radius key/full-height)]
+ (union
+ (->> spin-shape
+ (rotate (* α -1/2) [1 0 0]))))))
+
+(defn thumb-2x-row [shape]
+ (let [α (/ π 12)
+ radius (/ (/ key/pillar-depth 2)
+ (Math/sin (/ α 2)))
+ spin-shape (->> shape
+ (translate [0 0 (+ (- key/full-height)
+ (- radius))]))]
+ (translate
+ [0 0 (+ radius key/full-height)]
+ (union
+ (->> spin-shape
+ (rotate (* α 1) [1 0 0]))))))
+
+
+(defn spin-thumb [column shape]
+ (let [β (/ π 36)
+ radius (/ (/ (+ key/pillar-width 5) 2)
+ (Math/sin (/ β 2)))]
+ (->>
+ (translate
+ [0 0 (- (- radius key/full-height))]
+ (->> shape
+ (translate [0 0 (- radius key/full-height)])
+ (rotate (* column β) [0 1 0])))
+ (translate [key/pillar-width 0 0])
+ (rotate (/ π 12) [0 0 1])
+ #_(rotate (/ π -12) [0 1 0])
+ #_(rotate (/ π 6) [0 0 1])
+ (translate [-7 -47 35]))))
+
+(defn thumb-layout [shape]
+ (union
+ (spin-thumb 2 (thumb-x+x-column shape))
+ (spin-thumb 1 (thumb-x+x-column shape))
+ (spin-thumb 0 (thumb-2x-column shape))
+ (spin-thumb 1/2 (thumb-2x-row shape))))
+
+(defn support [shape]
+ (hull
+ shape
+ (extrude-linear {:height 10 :twist 0 :convexity 0}
+ (project (hull shape)))))
+
+(defn thumb-support [shape]
+ (union
+ (support (union
+ (spin-thumb 2 (thumb-x+x-column shape))
+ (spin-thumb 1 (thumb-x+x-column shape))
+ (spin-thumb 0 (thumb-2x-column shape))))
+ (support (union
+ (spin-thumb 0 (thumb-2x-column shape))
+ (spin-thumb 1/2 (thumb-2x-row shape))))
+
+))
+
+(def bottom
+ (translate [0 0 -100]
+ (cube 2000 2000 200))
+ )
+
+
+#_(def thumb-base
+ (difference
+ (hull
+ (thumb-layout (translate [0 0 (/ key/pillar-height -2)]
+ (scale [1 1 1/10] key/full-pillar)))
+ (extrude-linear {:height 10 :twist 0 :convexity 0}
+ (project (hull (thumb-layout key/full-pillar)))))
+ bottom
+ (thumb-layout key/keyswitch-full-hole)))
+
+(def thumb-base
+ (union
+ (thumb-support (scale [1 1 1/10] key/full-pillar))
+ #_(->> (cube 150 150 50)
+ (translate [150 75 25])))
+
+ )
+
+(defn move-to-corner [shape]
+ (translate [-265 -215 0] shape))
+
+(def thumb-cluster
+ (difference
+ (translate [0 0 -20]
+ (difference
+ (union
+ (thumb-layout key/pillar)
+ thumb-base)
+ (thumb-layout key/keyswitch-full-hole)))
+ bottom))
+
+(spit "alternathumb.scad"
+ (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
+ #_thumb-cluster
+ (union
+ (mirror [1 0 0] (move-to-corner thumb-cluster))
+ #_(->> (move-to-corner thumb-cluster)
+ (mirror [1 0 0]))
+ #_cave/base
+ #_cave/fingers
+ )
+
+ #_(mirror [1 0 0]
+ (difference
+ (move-to-corner thumb-cluster)
+ cave/base
+ ))
+ )))
+
diff --git a/src/dactyl_cave/cave.clj b/src/dactyl_cave/cave.clj
new file mode 100644
index 0000000..05bfaed
--- /dev/null
+++ b/src/dactyl_cave/cave.clj
@@ -0,0 +1,337 @@
+(ns dactyl-cave.cave
+ (:use [scad-clj.scad])
+ (:use [scad-clj.model])
+ (:use [unicode-math.core])
+ (:use [dactyl-cave.key]))
+
+(defn key-place [column row shape]
+ (let [α (/ π 12)
+ row-radius (+ (/ (/ pillar-depth 2)
+ (Math/sin (/ α 2)))
+ full-height)
+ row-placed-shape (->> shape
+ (translate [0 0 (- row-radius)])
+ (rotate (* α (- 2 row)) [1 0 0])
+ (translate [0 0 row-radius]))
+ β (/ π 36)
+ column-radius (+ (/ (/ (+ pillar-width 127/90) 2)
+ (Math/sin (/ β 2)))
+ full-height)
+ column-offset (condp = column
+ 2 [0 127/45 -254/45]
+ 4 [0 (/ pillar-depth -3) 254/45]
+ 5 [0 (/ pillar-depth -4) 254/45]
+ [0 0 0])
+ column-angle (if (<= column 4)
+ (* β (- 2 column))
+ (* β -3.25))
+ placed-shape (->> row-placed-shape
+ (translate [0 0 (- column-radius)])
+ (rotate column-angle [0 1 0])
+ (translate [0 0 column-radius])
+ (translate column-offset))]
+ (translate [0 0 127/18]
+ (rotate (/ π 12) [0 1 0]
+ placed-shape))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Limits
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(def bottom-limit
+ (->> (cube (* pillar-width 17.75)
+ (* pillar-depth 17)
+ 508/9)
+ (translate [(+ (/ pillar-width 2) 127/45)
+ 0 -254/9])))
+
+(def back-limit
+ (->> (cube (* pillar-width 9)
+ (* pillar-depth 2)
+ 254/3)
+ (translate [pillar-width
+ (+ (* pillar-depth 4.1))
+ 254/9])))
+
+(def front-right-limit
+ (->> (cube (* pillar-width 2)
+ (* pillar-depth 2)
+ 254/3)
+ (translate [(+ (* pillar-width 4.125))
+ (+ (* pillar-depth -3.25))])))
+
+(def front-left-limit
+ (->> (cube (* pillar-width 2.5)
+ (* pillar-depth 2)
+ 254/3)
+ (translate [(+ (* pillar-width -3))
+ (+ (* pillar-depth -3))
+ 254/9])))
+
+(def front-limit
+ (->> (cube (* pillar-width 9)
+ (* pillar-depth 2)
+ 254/3)
+ (translate [(* pillar-width 1/2) (+ (* pillar-depth -4.25)) 254/9])))
+
+ (* (/ 25.4 90) pillar-depth (- 3.1 -3.2))
+
+
+(def left-limit
+ (->> (cube (* pillar-width 1)
+ (* pillar-depth 8)
+ 254/3)
+ (translate [(+ (* pillar-depth -3.25)) 0 254/9])))
+
+(def right-limit
+ (->> (cube (* pillar-width )
+ (* pillar-depth 8)
+ 1016/9)
+ (translate [(+ (* pillar-depth 5.5)) 0 254/9])) )
+
+(* (/ 25.4 90) (- (- (* pillar-depth 5.4) (* pillar-width 1/2))
+ (+ (* pillar-depth -3.25) (* pillar-width 1/2))
+ ))
+
+(def limits
+ (union
+ #_front-right-limit
+ front-left-limit
+ front-limit
+ left-limit
+ right-limit
+ bottom-limit
+ back-limit))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Base
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(def main-sphere
+ (let [radius (/ (/ pillar-depth 2)
+ (Math/sin (/ (/ π 36) 2)))]
+ (->> (sphere radius)
+ (translate [(* pillar-width 2.5) 0 (+ radius 127/90)]))) )
+
+(def base-cube
+ (->> (cube (* pillar-width 7.75)
+ (* pillar-depth 7)
+ 508/9)
+ (translate [(+ (/ pillar-width 2) 2921/450)
+ 0 254/9])))
+
+(def base
+ (difference
+ base-cube
+ main-sphere
+ limits))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Walls
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#_(def wall-sphere
+ (let [radius (/ (/ pillar-depth 2)
+ (Math/sin (/ (/ π 36) 2)))]
+ (->> (sphere radius)
+ (scale [1 2/3 1])
+ (translate [(* pillar-width 2.5) 0 (+ radius 5 (* pillar-depth ))]))))
+
+(def wall-sphere
+ (let [radius (/ (/ pillar-depth 2)
+ (Math/sin (/ (/ π 36) 2)))]
+ (->> (sphere radius)
+ (scale [1 2/3 1])
+ (translate [0 0 radius])
+ (translate [0 0 127/18])
+ (rotate (/ π 12) [0 1 0])
+ (translate [0 0 (* pillar-depth 3/4)]))))
+
+(def wall-thickness 127/30)
+
+(def back-wall
+ (difference
+ (translate [0 (- wall-thickness) 0] back-limit)
+ back-limit
+ right-limit
+ left-limit
+ bottom-limit
+ wall-sphere))
+
+(def walls
+ (difference
+ (union
+ (translate [0 (- wall-thickness) 0] back-limit)
+ (translate [(- wall-thickness) 0 0] right-limit)
+ (translate [0 wall-thickness 0] front-limit)
+ (translate [wall-thickness 0 0] left-limit)
+ )
+ wall-sphere
+ limits))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Wire holes
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(def teensy-center [(* -1.6 pillar-width)
+ (* 2.8 pillar-depth)
+ 254/45])
+
+(def teensy-tray-slot
+ (->> (cube (* 1.125 pillar-width)
+ 40
+ 508/45)
+ (translate teensy-center)))
+
+(def hole-destination
+ (->> (cube 5.7 5.7 5.7)
+ (translate [(first teensy-center)
+ (second teensy-center)
+ 2.8 #_3.1])))
+
+(defn bottom-cube [column row]
+ (->> (cube 6 6 6)
+ (key-place column row)
+ (project)
+ (extrude-linear {:height 5.7 :twist 0 :convexity 0})
+ (translate [0 0 2.8])))
+
+(defn wire-hole [column row]
+ (union
+ (hull
+ (key-place column row (cube 6 6 keyswitch-height))
+ (bottom-cube column row))
+ (hull
+ hole-destination
+ (bottom-cube column row))))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Full Model
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(def fingers
+ (let [all-key-coords (for [column (range 0 6)
+ row (range 0 5)
+ ;; Removing bottom left key
+ :when (or (not= column 0)
+ (not= row 4))]
+ [column row])
+ middle-key-coords (for [column (range 0 6)
+ row (range 1 4)
+ ;; Removing bottom left key
+ :when (or (not= column 0)
+ (not= row 4))]
+ [column row])
+ top-key-coords (for [column (range 0 6)]
+ [column 0])
+ bottom-key-coords (conj (for [column (range 1 6)]
+ [column 4])
+ [0 3])
+
+ ]
+ (difference
+ (union base
+ #_walls
+ (apply union
+ (map #(key-place (first %) (second %)
+ (->> (cube pillar-width pillar-depth
+ (* 3 pillar-height))
+ (translate [0 0 (/ pillar-height -2)])))
+ all-key-coords)))
+ (apply union
+ (concat
+ (map #(key-place (first %) (second %) keyswitch-full-hole)
+ middle-key-coords)
+ (map #(key-place (first %) (second %) keyswitch-bottom-hole)
+ top-key-coords)
+ (map #(key-place (first %) (second %) (mirror [0 -1 0] keyswitch-bottom-hole))
+ bottom-key-coords)
+ ))
+ limits
+ teensy-tray-slot)))
+
+
+(def wire-network
+ (union
+ (wire-hole 0 0)
+ (wire-hole 1 0)
+ (wire-hole 2 0)
+ (wire-hole 3 0)
+ (wire-hole 4 0)
+ (wire-hole 5 0)
+ (wire-hole 0 1)
+ (wire-hole 0 2)
+ (wire-hole 0 3)
+ (wire-hole 0 4)
+ (wire-hole 1 4)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Actual Output
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#_(spit "key.scad"
+ (write-scad (difference
+ pillar
+ )))
+
+(spit "key.scad"
+ (write-scad (difference
+ (union
+ #_walls
+ #_wall-sphere
+ #_fingers
+ (difference fingers wire-network)
+ #_(mirror [-1 0 0]
+ (difference fingers wire-network))
+ )
+ #_(cube 400 800 800)
+ )))
+
+#_(spit "key.scad"
+ (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
+ (difference
+ (union
+ #_walls
+ #_wall-sphere
+ #_fingers
+ (difference fingers wire-network)
+ #_(mirror [-1 0 0]
+ (difference fingers wire-network))
+ )
+ #_(cube 400 800 800)
+ ))))
+
+
+#_(spit "key.scad"
+ (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
+ (difference
+ fingers
+ wire-hole-1
+ wire-hole-2))))
+
+#_(spit "key.scad"
+ (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
+ (differe
+ #_wall
+ #_base
+ #_rim
+ #_(mirror [1 0 0] fingers)
+ fingers
+ wire-hole-1))))
+
+#_(spit "key.scad"
+ (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
+ (union
+ fingers
+ (->> fingers
+ project
+ (extrude-linear {:height 1 :twist 0 :convexity 0})
+ (scale [1.5 1.15 1])
+ )
+ )
+ )))
+
diff --git a/src/dactyl_cave/core.clj b/src/dactyl_cave/core.clj
new file mode 100644
index 0000000..d07faa6
--- /dev/null
+++ b/src/dactyl_cave/core.clj
@@ -0,0 +1,6 @@
+(ns dactyl-cave.core)
+
+(defn foo
+ "I don't do a whole lot."
+ [x]
+ (println x "Hello, World!"))
diff --git a/src/dactyl_cave/key.clj b/src/dactyl_cave/key.clj
new file mode 100644
index 0000000..13c46fd
--- /dev/null
+++ b/src/dactyl_cave/key.clj
@@ -0,0 +1,81 @@
+(ns dactyl-cave.key
+ (:use [scad-clj.scad])
+ (:use [scad-clj.model])
+ (:use [unicode-math.core]))
+
+
+(def tw 13.969999999999999) ;; Top width
+(def smh 0.98044) ;; Side margin height
+(def pw 0.8128) ;; Peg width
+(def ph 3.5001199999999995) ;; Peg height
+(def pgh 5.00888) ;; Peg gap height
+
+(def keyswitch-height (+ smh ph pgh ph smh))
+(def keyswitch-width (+ pw tw pw))
+(def plate-height 254/45)
+
+(defn- flip-path [points] (map (partial map -) points))
+
+(def keyswitch-plate-hole-shape
+ (polygon [[0.8128 0] [0.8128 0.98044] [0.0 0.98044] [0.0 4.48056] [0.8128 4.48056] [0.8128 9.48944] [0.0 9.48944] [0.0 12.98956] [0.8128 12.98956] [0.8128 13.969999999999999] [14.7828 13.969999999999999] [14.7828 12.98956] [15.5956 12.98956] [15.5956 9.48944] [14.7828 9.48944] [14.7828 4.48056] [15.5956 4.48056] [15.5956 0.98044] [14.7828 0.98044] [14.7828 0]]))
+
+(def keyswitch-plate-hole
+ (->> keyswitch-plate-hole-shape
+ (extrude-linear {:height plate-height :twist 0 :convexity 0})
+ (translate (map #(/ (- %) 2) [keyswitch-width keyswitch-height 0]))
+ (translate [0 0 1])))
+
+(def hole-height 127/18)
+
+(def pillar-width (+ keyswitch-width 127/45))
+(def pillar-height (+ hole-height (/ plate-height 2)))
+(def pillar-depth (+ keyswitch-height 127/30))
+
+(def keyswitch-full-hole
+ (->>
+ (union
+ keyswitch-plate-hole
+ (->> (cube (/ ph 2) pillar-depth (* plate-height 2))
+ (translate [(* tw -1/4) 0 0]))
+ (->> (cube (/ ph 2) pillar-depth (* plate-height 2))
+ (translate [(* tw 1/4) 0 0]))
+ (translate
+ [0 0 (/ hole-height -2)]
+ (cube keyswitch-width
+ keyswitch-height
+ hole-height)))
+ (translate [0 0 hole-height])))
+
+(def keyswitch-bottom-hole
+ (->>
+ (union
+ keyswitch-plate-hole
+ (->> (cube (/ ph 2) (/ pillar-depth 2) (* plate-height 2))
+ (translate [(* tw -1/4) (/ pillar-depth -2) 0]))
+ (->> (cube (/ ph 2) (/ pillar-depth 2) (* plate-height 2))
+ (translate [(* tw 1/4) (/ pillar-depth -2) 0]))
+ (translate
+ [0 0 (/ hole-height -2)]
+ (cube keyswitch-width
+ keyswitch-height
+ hole-height)))
+ (translate [0 0 hole-height])))
+
+(def full-pillar
+ (->> (cube pillar-width pillar-depth
+ pillar-height)
+ (translate [0 0 (/ pillar-height 2)])))
+
+(def pillar
+ (difference
+ full-pillar
+ keyswitch-full-hole))
+
+(def key-height 127/10)
+
+(def pillar-with-fake-key
+ (union pillar
+ (->> (cube (+ -0 pillar-width) (+ -0 pillar-depth) key-height)
+ (translate [0 0 (+ (/ key-height 2) pillar-height 127/450)]))))
+
+(def full-height (+ pillar-height key-height 127/450))
diff --git a/src/dactyl_cave/text.clj b/src/dactyl_cave/text.clj
new file mode 100644
index 0000000..db37bfd
--- /dev/null
+++ b/src/dactyl_cave/text.clj
@@ -0,0 +1,134 @@
+(ns dactyl-cave.text
+ (:use [scad-clj.scad])
+ (:use [scad-clj.model])
+ (:import (java.awt Font RenderingHints)
+ (java.awt.font FontRenderContext)
+ (java.awt.geom PathIterator)))
+
+(def segment-type
+ {PathIterator/SEG_CLOSE :close
+ PathIterator/SEG_CUBICTO :cubic-to
+ PathIterator/SEG_LINETO :line-to
+ PathIterator/SEG_MOVETO :move-to
+ PathIterator/SEG_QUADTO :quad-to})
+
+;; How many points are specified for each segment type
+(def segment-length
+ {PathIterator/SEG_CLOSE 0
+ PathIterator/SEG_CUBICTO 3
+ PathIterator/SEG_LINETO 1
+ PathIterator/SEG_MOVETO 1
+ PathIterator/SEG_QUADTO 2})
+
+(defn path-iterator->segments
+ "Converts a PathIterator into a sequence of segments of the form [segment-type [& points]]"
+ [^PathIterator path-iterator]
+ (if (not (.isDone path-iterator))
+ (let [coords (double-array (* 2 (apply max (vals segment-length))))
+ segment-code (.currentSegment path-iterator coords)]
+ (cons [(segment-type segment-code)
+ (take (segment-length segment-code) (partition 2 coords))]
+ (lazy-seq (path-iterator->segments (doto path-iterator (.next))))))))
+
+(defn quad->fn
+ "Returns the parametric control equation f(t), 0 <= t <= 1
+for the quadratic interpolation of 3 points."
+ [cp p1 p2]
+ (fn [t]
+ (letfn [(interp [a b c] (+ (* (Math/pow (- 1 t) 2) a)
+ (* 2 t (- 1 t) b)
+ (* (Math/pow t 2) c)))]
+ [(apply interp (map first [cp p1 p2]))
+ (apply interp (map second [cp p1 p2]))])))
+
+(defn cubic->fn
+ "Returns the parametric control equation f(t), 0 <= t <= 1
+for the cubic interpolation of 4 points."
+ [cp p1 p2 p3]
+ (fn [t]
+ (letfn [(interp [a b c d]
+ (+ (* (Math/pow (- 1 t) 3) a)
+ (* 3 t (Math/pow (- 1 t) 2) b)
+ (* 3 (Math/pow t 2) (- 1 t) c)
+ (* (Math/pow t 3) d)))]
+ [(apply interp (map first [cp p1 p2 p3]))
+ (apply interp (map second [cp p1 p2 p3]))])))
+
+(defn segments->lines
+ "Takes a sequence of segments of the form [segment-type [& points]]
+and transforms each segment into a sequence of interpolated points"
+ [segments]
+ (reductions (fn [prev-line-points [segment-type control-points]]
+ #_(println segment-type)
+ (condp = segment-type
+ :move-to control-points
+ :line-to control-points
+ :quad-to (map (apply quad->fn
+ (last prev-line-points)
+ control-points)
+ (range 1/10 11/10 1/10))
+ :cubic-to (map (apply cubic->fn
+ (last prev-line-points)
+ control-points)
+ (range 1/10 11/10 1/10))))
+ (last (rest (first segments)))
+ (rest segments)))
+
+
+(defn path2d [points]
+ (let [path (doto (java.awt.geom.Path2D$Double.)
+ (.moveTo (-> points first first)
+ (-> points first second)))]
+ (doseq [point (rest points)]
+ (.lineTo path (first point) (second point)))
+ path))
+
+(defn split-intersecting [paths]
+ (let [polygons (map path2d paths)
+ starting-points (map first paths)]
+ (reduce (fn [acc path]
+ (let [polygon (path2d path)]
+ (if (some #(.contains % (-> path first first) (-> path first second))
+ (:polygons acc))
+ (merge-with concat acc
+ {:difference [path]})
+ (merge-with concat acc
+ {:polygons [polygon]
+ :union [path]}))))
+ {:polygons []
+ :union []
+ :difference []}
+ paths)))
+
+(defn text-polygon [font size text]
+ (let [frc (FontRenderContext. nil
+ RenderingHints/VALUE_TEXT_ANTIALIAS_DEFAULT
+ RenderingHints/VALUE_FRACTIONALMETRICS_DEFAULT)
+ path-iter (-> (Font. font Font/PLAIN size)
+ (.createGlyphVector frc text)
+ (.getOutline)
+ (.getPathIterator nil))
+ paths (->> (path-iterator->segments path-iter)
+ (partition-by #(= (first %) :close))
+ (take-nth 2)
+ (map segments->lines)
+ (map flatten)
+ (map (partial partition 2)))
+ split-paths (split-intersecting paths)]
+ (difference
+ (apply union (map polygon (:union split-paths)))
+ (apply union (map polygon (:difference split-paths))))))
+
+(spit "/Users/madereth/text.scad"
+ (write-scad
+ (->> "Anonymous Pro" #_(str (java.util.Date.))
+ (text-polygon "Anonymous Pro" 12)
+ (extrude-linear {:height 50 :twist 0 :convexity 0}))))
+
+
+
+(spit "/Users/madereth/text.scad"
+ (write-scad
+ (->> "Anonymous Pro" #_(str (java.util.Date.))
+ (text-polygon "Anonymous Pro" 12)
+ (extrude-linear {:height 12 :twist 0 :convexity 0})))) \ No newline at end of file
diff --git a/src/dactyl_cave/thumb.clj b/src/dactyl_cave/thumb.clj
new file mode 100644
index 0000000..0dfce97
--- /dev/null
+++ b/src/dactyl_cave/thumb.clj
@@ -0,0 +1,173 @@
+(ns dactyl-cave.thumb
+ (:use [scad-clj.scad])
+ (:use [scad-clj.model])
+ (:use [unicode-math.core])
+ (:require [dactyl-cave.key :as key])
+ (:require [dactyl-cave.cave :as cave]))
+
+(defn thumb-place [column row shape]
+ (let [α (/ π 12)
+ row-radius (+ (/ (/ key/pillar-depth 2)
+ (Math/sin (/ α 2)))
+ key/full-height)
+ β (/ π 36)
+ column-radius (+ (/ (/ (+ key/pillar-width 5) 2)
+ (Math/sin (/ β 2)))
+ key/full-height)]
+ (->> shape
+ (translate [0 0 (- row-radius)])
+ (rotate (* α row) [1 0 0])
+ (translate [0 0 row-radius])
+ (translate [0 0 (- column-radius)])
+ (rotate (* column β) [0 1 0])
+ (translate [0 0 column-radius])
+ (translate [key/pillar-width 0 0])
+ (rotate (/ π 12) [0 1 0])
+ (rotate (* π (- 1/4 1/16)) [0 0 1])
+ (rotate (/ π 12) [1 1 0])
+ (translate [254/45 127/15 1778/45]))))
+
+(defn thumb-2x-column [shape]
+ (thumb-place 0 -1/2 shape))
+
+(defn thumb-2x+1-column [shape]
+ (union (thumb-place 1 -1/2 shape)
+ (thumb-place 1 1 shape)))
+
+(defn thumb-1x-column [shape]
+ (union (thumb-place 2 -1 shape)
+ (thumb-place 2 0 shape)
+ (thumb-place 2 1 shape)))
+
+(defn thumb-layout [shape]
+ (union
+ (thumb-2x-column shape)
+ (thumb-2x+1-column shape)
+ (thumb-1x-column shape)))
+
+(defn support [shape]
+ (hull
+ shape
+ (extrude-linear {:height 127/45 :twist 0 :convexity 0}
+ (project (hull shape)))))
+
+(defn thumb-support [shape]
+ (let [column-supports
+ (union
+ (support (thumb-2x-column shape))
+ (support (thumb-2x+1-column shape))
+ (support (thumb-1x-column shape)))]
+ (union column-supports
+ (support column-supports))))
+(fn [])
+(def bottom
+ (translate [0 0 -254/9] (cube 5080/9 5080/9 508/9)))
+
+(def thumb-base
+ (thumb-support (scale [1 1 1/10] key/full-pillar)))
+
+#_(defn move-to-corner [shape]
+ (translate [-6731/90 -5461/90 0] shape))
+
+(defn move-to-corner [shape]
+ (translate [(+ -6731/90 10) (- -5461/90 10) 0] shape))
+
+(/ -6731 90.0) -74.78888888888889
+(double -5461/90) -60.67777777777778
+
+(def thumb-cluster
+ (difference
+ (translate [0 0 -254/45]
+ (difference
+ (union
+ (thumb-layout key/pillar)
+ thumb-base)
+ (thumb-layout key/keyswitch-full-hole)))
+ bottom))
+
+(def connection-stems
+ (difference
+ (hull (union
+ (->> (cylinder 127/90 508/9)
+ (translate [-0 -2413/45 0]))
+ (->> (cylinder 127/90 508/9)
+ (translate [-127/3 -0 0]))
+ (->> (cylinder 127/90 508/9)
+ (translate [-2159/30 -127/5 0]))
+ (->> (cylinder 127/90 508/9)
+ (translate [-508/9 -381/5 0]))))
+ bottom
+ cave/main-sphere
+ (translate [0 0 -254/45]
+ (thumb-layout key/keyswitch-full-hole))))
+
+(def wire-network
+ (apply union
+ (for [[column row] [[0 -1/2]
+ [1 -1/2]
+ [1 1]
+ [2 -1]
+ [2 0]
+ [2 1]]]
+ (let [middle-hole (->> (thumb-place column row (cube 6 6 6))
+ (translate [0 0 -127/9])
+ move-to-corner)]
+ #_(thumb-place column row (sphere 127/9))
+ (union (hull (->> (cube 254/45 254/45 key/keyswitch-height)
+ (thumb-place column row)
+ move-to-corner)
+ middle-hole)
+ (hull middle-hole (cave/bottom-cube 0 4))
+ (hull (cave/bottom-cube 0 4) cave/hole-destination))))))
+
+
+(spit "thumb.scad"
+ (write-scad (difference
+ (union
+ (move-to-corner thumb-cluster)
+ connection-stems
+
+ #_cave/base
+ #_cave/fingers)
+ cave/base
+ wire-network)))
+
+#_(spit "thumb.scad"
+ (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
+ (mirror [-1 0 0]
+ (difference
+ (union
+ (move-to-corner thumb-cluster)
+ connection-stems
+
+ #_cave/base
+ #_cave/fingers)
+ cave/base
+ wire-network)))))
+
+#_(spit "thumb.scad"
+ (write-scad (scale [(/ 25.4 90) (/ 25.4 90) (/ 25.4 90)]
+ (mirror [-1 0 0]
+ (difference
+ (union
+ (move-to-corner thumb-cluster)
+ connection-stems
+
+ #_cave/base
+ #_cave/fingers)
+ cave/base
+ wire-network)))))
+
+
+
+
+(spit "one-piece.scad"
+ (write-scad
+ (mirror [-1 0 0]
+ (union (difference cave/fingers cave/wire-network)
+ (difference
+ (union
+ (move-to-corner thumb-cluster)
+ connection-stems)
+ cave/base
+ wire-network)))))
diff --git a/src/scad_demo/core.clj b/src/scad_demo/core.clj
new file mode 100644
index 0000000..ad59891
--- /dev/null
+++ b/src/scad_demo/core.clj
@@ -0,0 +1,11 @@
+(ns scad-demo.core
+ (:use [scad-clj.scad])
+ (:use [scad-clj.model]))
+
+(def primitives
+ (union
+ (union)
+ (->> (sphere 50))))
+
+(spit "post-demo.scad"
+ (write-scad primitives)) \ No newline at end of file
diff --git a/target/classes/META-INF/maven/dactyl-cave/dactyl-cave/pom.properties b/target/classes/META-INF/maven/dactyl-cave/dactyl-cave/pom.properties
new file mode 100644
index 0000000..4ef3836
--- /dev/null
+++ b/target/classes/META-INF/maven/dactyl-cave/dactyl-cave/pom.properties
@@ -0,0 +1,6 @@
+#Leiningen
+#Wed Mar 04 17:30:05 PST 2015
+version=0.1.0-SNAPSHOT
+revision=9e72dea9b02c89fb782537b8e1af7cda4f11c995\n
+groupId=dactyl-cave
+artifactId=dactyl-cave
diff --git a/target/repl-port b/target/repl-port
new file mode 100644
index 0000000..499386f
--- /dev/null
+++ b/target/repl-port
@@ -0,0 +1 @@
+52476 \ No newline at end of file
diff --git a/target/stale/extract-native.dependencies b/target/stale/extract-native.dependencies
new file mode 100644
index 0000000..5613b75
--- /dev/null
+++ b/target/stale/extract-native.dependencies
@@ -0,0 +1 @@
+([:dependencies ([cider/cider-nrepl "0.8.0"] [org.clojure/clojure "1.5.1"] [unicode-math/unicode-math "0.2.0"] [scad-clj/scad-clj "0.1.0"] [org.clojure/tools.nrepl "0.2.6" :exclusions ([org.clojure/clojure]) :scope "test"] [clojure-complete/clojure-complete "0.2.3" :exclusions ([org.clojure/clojure]) :scope "test"])]) \ No newline at end of file
diff --git a/test/dactyl_cave/core_test.clj b/test/dactyl_cave/core_test.clj
new file mode 100644
index 0000000..2259ab4
--- /dev/null
+++ b/test/dactyl_cave/core_test.clj
@@ -0,0 +1,7 @@
+(ns dactyl-cave.core-test
+ (:require [clojure.test :refer :all]
+ [dactyl-cave.core :refer :all]))
+
+(deftest a-test
+ (testing "FIXME, I fail."
+ (is (= 0 1))))