├── .gitignore
├── README.md
├── notes
├── diy_plotters.md
├── pictures
│ └── plotter-hardware
│ │ ├── idraw_z_axis.jpg
│ │ ├── iv_project.jpg
│ │ ├── lumenpnp.jpg
│ │ └── pinion.jpg
├── plotter_hardware_designs.md
├── plotter_notes.md
├── product_codes.md
├── protocols.md
├── prtocols_big.csv
├── random_links.md
├── supplies.md
└── vintage_plotter_links.md
├── other_testplots
├── DMP-60.png
├── atari_1020_color_printer.png
├── calcomp_artisan_102x.png
├── dmp_60.png
├── dxy-800_dxy-101.png
├── hp7475a.png
├── hp7585.png
├── hp_draft_pro.png
├── readme.md
├── roland-dxy-880.png
├── roland_2.png
├── roland_dpx-2000.png
├── roland_dpx-3300.png
└── tektronix_4662.png
├── test_plot
├── Readme.md
├── shift_compact.svg
├── test_cal_plot_A4.svg
└── test_cal_plot_A4_exported.svg
├── turtletoy
├── flower.js
├── glyph.js
├── hex_grid.js
├── sprio1.js
└── truchet_snowflakes.js
└── vsvg
├── dither_hatch
├── Cargo.lock
├── Cargo.toml
└── src
│ └── main.rs
└── simple
├── Cargo.lock
├── Cargo.toml
├── examples
├── christmas_tree.rs
├── circles.rs
├── circles2.rs
├── mst.rs
├── pattern_1.rs
└── snowfl.rs
├── readme.md
└── src
└── main.rs
/.gitignore:
--------------------------------------------------------------------------------
1 | vsvg/*/target
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # plotter_sketches
2 | Various sketches for pen plotters
3 |
--------------------------------------------------------------------------------
/notes/diy_plotters.md:
--------------------------------------------------------------------------------
1 | TODO:
2 |
3 | ## Commonly used parts
4 |
5 | * Nema17 stepper motors (could use other sizes as well, but these are most common and easily available and usually don't need bigger ones in a pen plotter)
6 | * 28BYJ-48 stepper motors (not recommended unless you are going for <$80 build budget, out of the box these will not work with many controller CNC/3d printer firmwares/stepper drivers)
7 | * controller board -> recommended to search for "3d printer motherboard". You can get a decent modern board for $25-$50. Some manufacturers:
8 | - BIGTREETECH / BIQU
9 | - fysetc
10 | - MKS
11 | * (not recommended) boards mentioning Arduino, RAMPS or arduino CNC shield .
12 | * stepper motor driver boards
13 | - some controller boards have builtin
14 | - other boards have sockets for step stick format driver boards
15 | - driver based on TMC chip are recommended (at the time of writing these notes)
16 | - larger format standalone stepper drivers are unlikely to be necessary for motors that you would use in a pen plotter
17 | * Linear rails
18 | * Linear bearings common size LM8UU
19 | * Aluminum extrusion (for frame) commonly used 2020 series. There are variations 2x1, 3x1 and other variations which are 40x20 and 60x20 mm accordingly. Usually used together with matching angle brackets and t-nuts. Notes. Note that there are various other similar looking aluminum extrusion systems which have incompatible dimensions. Also 80/20 extrusions often instead referring to 4x1 2020 series profile (which have dimensions of 80x20mm), instead means one of the aluminum extrusions made by company called "80/20" which have multiple extrusion systems including some that are based on inches instead of metric units.
20 | * V-wheels for matching aluminum extrusions. You can also buy ready mount plates with 3-4 wheels, with builtin mechanism for adjusting tension.
21 | * Belts and pulleys for them. Most common type used in 3d printers -> GT2 6mm.
22 | - belt
23 | - drive pulley for mounting on stepper motor shaft, with grubscrew for locking it in place on D shaped shaft
24 | - toothed and smooth idler pulleys depending on belt routing
25 |
26 | ## Source of inspiration/existing models
27 |
28 | If you are looking for inspiration or an existing design to build checkout websites with models for 3d printing, and posting diy projects. Recommended keywords for search "plotter", "pen plotter", "drawingbot". The later two will have more projects which are using mix of different techniques not just 3d printing.
29 |
30 | 3d printing
31 | * [Printables](https://www.printables.com/search/models?q=plotter)
32 | * [various pen plotters](https://www.printables.com/@Kabacis_332837/collections/1870431)
33 | * [drawingmachines](https://www.printables.com/search/models?q=tag%3Adrawingmachine)
34 | * [penplotter](https://www.printables.com/search/models?q=tag%3Apenplotter)
35 | * [plotter](https://www.printables.com/search/models?q=tag%3Aplotter)
36 | * [Thingiverse](https://www.thingiverse.com/search?q=plotter)
37 | * [various pen plotters](https://www.thingiverse.com/karliss/collections/43091126/things)
38 | * [subassemblies](https://www.thingiverse.com/karliss/collections/43091129/things)
39 | * [Makerworld](https://makerworld.com/en/search/models?keyword=plotter)
40 | * [Thagns](https://thangs.com/search/pen%20plotter?scope=all)
41 |
42 | All kind of DIY projects:
43 | * [hackaday.io](https://hackaday.io/search?term=pen+plotter)
44 | * [instructables](https://www.instructables.com/search/?q=plotter&projects=all)
45 |
46 | * https://www.instructables.com/CNC-Plotter-1/ (lingib)
47 | * https://howtomechatronics.com/projects/diy-pen-plotter-with-automatic-tool-changer-cnc-drawing-machine/
48 |
49 |
50 | ## Lifter designs
51 |
52 |
53 | * https://www.printables.com/model/868919-generative-pen-plotter-art-cnc-arduino-vinyl-cutte#preview.80Yeb (string stepper)
54 | * https://discord.com/channels/929089222118359100/1133548294925209814/1188035146457284668 (idraw clone)
55 | * https://discord.com/channels/499297341472505858/499298106035273770/1323441263625638039 (belt string)
56 | * https://discord.com/channels/929089222118359100/1191870618187087992/1331014811848413265 (belt loop, 2 sliders on one rail)
57 |
58 |
59 | # Various builds
60 | * https://github.com/DanniDesign/Ploxy/tree/main
61 | * https://github.com/jamescarruthers/PlotteRXY
62 | * https://www.thingiverse.com/thing:6841321
63 |
64 | # Pen changer builds
65 |
66 | * https://www.youtube.com/watch?v=GGtdwYdZWi8
67 | * https://howtomechatronics.com/projects/diy-pen-plotter-with-automatic-tool-changer-cnc-drawing-machine/
68 |
69 | * https://www.youtube.com/watch?v=qAdHhoz2k2I
70 |
71 | * https://www.youtube.com/watch?v=JuZ5lk2J5p4
72 | * https://www.youtube.com/watch?v=CpA98QtHj4s
73 |
74 | * https://www.doublejumpelectric.com/projects/toolchanging_pen_plotter/2019-03-17-toolchanging_pen_plotter/
75 |
76 | * https://patents.google.com/patent/US4417258A/en
--------------------------------------------------------------------------------
/notes/pictures/plotter-hardware/idraw_z_axis.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/notes/pictures/plotter-hardware/idraw_z_axis.jpg
--------------------------------------------------------------------------------
/notes/pictures/plotter-hardware/iv_project.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/notes/pictures/plotter-hardware/iv_project.jpg
--------------------------------------------------------------------------------
/notes/pictures/plotter-hardware/lumenpnp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/notes/pictures/plotter-hardware/lumenpnp.jpg
--------------------------------------------------------------------------------
/notes/pictures/plotter-hardware/pinion.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/notes/pictures/plotter-hardware/pinion.jpg
--------------------------------------------------------------------------------
/notes/plotter_hardware_designs.md:
--------------------------------------------------------------------------------
1 | # Plotter product categories
2 |
3 | | Name | Price | Ease of use | Versatility | Performance |
4 | | :------------------ | :----- | ----------- | ----------- | --- |
5 | | Vintage pen plotter | $$ - $$$ | + | 0 | ++++ |
6 | | DIY | $ - $$$ | + | ++++ | +/+++ |
7 | | Modern pen plotters | $$$ | ++ | ++ | ++ |
8 | | Cheap kits | $ - $$ | + | ++ | ++ |
9 | | Toy plotters | $ | +++ | - | - |
10 | | Hobby vinyl cutters/plotters | $$ | +++ | ++ | ++ |
11 | | Vinyl cutters | $$ - $$$$ | +++ | + | ++ |
12 | | Pen attachment for your existing CNC device or 3d printer | $ | + | ++ | ++ |
13 |
14 |
15 | ## Vintage pen plotters
16 | There was a period of time when pen plotters served a similar role as office printers and for a slightly longer period for plotting large format engineering and architectural drawings.
17 | Somewhat wide commercial use meant that the machines were very well engineered and optimized for one specific task which resulted great performance even by modern standards. Lightweight construction allows fast movement and acceleration. But more impressively solenoid based pen lifting mechanism in some machines is capable of lifting the pen 20-30 times a second.
18 |
19 |
20 | One thing that might slightly held them back is limited computing power and data transfer rate. At their time this was partially compensated by having builtin commands for things like dotted lines, polygon fill and circles. Currently, unless you are making your own software for your specific drawing and plotter, you are more likely to generate arbitrary vector drawing and then convert it to the language plotter understand by splitting all lines into into short segments.
21 |
22 | Two major subcategories are flatbed plotters and roller based ones. For the flatbed ones paper stands still and the pen moves along x and y axes. This means that plotter needs to be bigger than the paper sheet you are drawing on and it takes a lot of space on the table. Some of them where designed to allow standing at angle, not quite vertically.
23 | Roller based ones use rollers to move paper back and forth along Y axis, with X axis being stationary, similar to how modern printers work. This approach was used both for desktop sized plotters, also large ones supporting up to A1 or A2 size paper.
24 |
25 | Depending on how well it's preserved you can find deals for $200-$600, broken ones sold as parts only in $50-$150 range. Since it's not that easy to run them with modern computer not all sellers can easily test if the plotter is in working state, so you can occasionally be lucky and find a working one sold as "parts only".
26 |
27 | As with any vintage device availability is of spare parts and consumables is limited. It will likely need some tinkering to keep it running. Some plastic parts might be broken, rubber deteriorated.
28 | If you are lucky someone has already designed and shared models for 3d printable replacements.
29 | These types of pen plotters are usually meant to be used with specially shaped stubby pens. You can find some old stock in the various marketplaces, but if you are going to do a lot of plots that can become costly. So you will also likely make an adapter for pens.
30 | One more problem with using modern pens is that the original pens were very short and rest of machine designed with that in mind. This is mostly a problem for roller based plotter with pen changers or a plastic cover over the moving parts. Flatbed plotters are more likely to be compatible with longer pens without any modifications except the mounting adapter.
31 |
32 | One bright side in terms of repairability is that at the time these plotters where made, manufacturers providing a service manual with full schematics and detailed troubleshooting steps was still common.
33 |
34 | The optimized design comes at the cost of versatility. Loading an arbitrary pen or paper can be problematic. Again flatbed plotters are slightly better as you can more or less place any paper or flat material smaller than maximum size, but the roller based ones will likely expect very specific paper sizes and fail to feed anything which isn't normal thickness office paper. Rollers can also be problematic if they go over any wet ink smudging it. You would at least hope that roller based plotters have infinite Y axis, that isn't always the case. Plenty of roller based plotters only support specific standard paper sheet sizes, and even if paper rolls are supported accuracy over for plots bigger than 1-2 meters isn't guaranteed.
35 | Well optimized design means limited Z axis movement range and pen pressure, so using anything which isn't a normal pen will likely not work.
36 |
37 | Other major drawback is related to ease of use of use, connection and software setup. It's not exactly a plug and play process. You will likely need a some kind special adapter for connecting to modern PC. And not every adapter will properly function with every device. After electrical connection, next challenge is connection parameters. Serial port has half dozen parameters which need to be configured exactly the same on the plotter and the software running on your computer. Consult the documentation of your plotter to find out correct values, don't attempt to guess randomly there are way too many different combinations. Often these can be changed on the plotter using dip switches on the back of plotter.
38 | Third step is the actual printing. Instead of trying to get drivers and configured like regular printer (with exception of drivers for adapter if needed) treat it like generic serial port like device. There is a bunch of software meant for either directly interfacing with such plotters, or converting svg to the language plotter understands and then you send the file using some other software. You can also write your own script which directly generates the drawing in language understood by your plotter. The languages used by plotters were very simple but somewhat high level at the same time compared to modern formats so it's not too difficult if you have some programming knowledge. Usually it's either HPGL or GPGL or something based on those two, but there can also be a bunch subtle differences between each machine. So check the manual especially if you are planning to use anything more advanced the move to position, draw straight line.
39 |
40 | While the speed for straight lines and pen lifting/lowering is quite good, CPUs in these plotters are somewhat slow. Drawing circles or other curves can be much slower compared to straight lines. Stepper driver technology also has advanced over the years. Modern stepper drivers like those made by Trinamics can be much quiter compared to vintage pen plotters.
41 |
42 |
43 | ## Modern pen plotters
44 | For most practical use cases pen plotters have been replaced by other printing technologies. Modern "Plotters" that you might find in architecture firms are just large size inkjet printers. This means that new commercial plotters is a very small niche, with few manufacturers.
45 |
46 | The small market means there is not enough money to make serious engineering effort optimizing the build for performance or price. Currently the 2 main sellers are Bantam tools (previously Evil mad scientist with Axidraw machines) and other is UUNA TEK with iDraw machines. Costing somewhere between $500-$1500 for A4-A2 sizes and up to $5000 for largest machines.
47 |
48 | If you compare the pen plotters to similar price medium/high end hobby 3d printer or low end CNC machines. Pen plotter by the requirements is already much simpler machine. But even with that advantage the modern pen plotters are much closer to DIY machines than they are to machines of other types or plotters from 40 years ago. This isn't meant to be an insult for the creators of those machines, more of an observation about reality of market and what happens when economies of scale and competition do not apply.
49 |
50 | For some people slightly smoother overall experience might be worth it.
51 |
52 | ## Toy plotters
53 |
54 | Different type of new commercially available pen plotters is sold as kids toy. Consisting of 3 hobby servos and using 5-bar linkage to move the pen. It usually costs ~$50-$100. The drawing area is very limited, maybe 15x15cm, and the accuracy isn't great either. Sometimes there are cards or something similar for drawing one of the builtin image (it's meant to be a kids toy they aren't supposed to need a computer for using it), there might be a mobile app which allows making custom drawings. Some examples: Line-us, WeDraw (canceled kicstarter), "Quincy The Robot Artist". Some of them have speaker for giving children instructions how to draw the same thing. Some are sold as barebone kit more as a STEM toy.
55 |
56 |
57 | ## Cheap kits or preassembled machines from Ebay/Aliexpress
58 | If you don't want to design a DIY machine or the previously mentioned prices are way above your budget you can find a bunch of relatively cheap machines from ebay/Aliexpress or other similar marketplaces.
59 | Costing ~$100-$150 for small sizes up to $400 for bigger ones. That's closer what you would expect considering the prices of 3d printers using the same parts.
60 |
61 | If you want to save money and are ready for little bit of DIY instead of buying bigger ones it will be cheaper to get the smallest one and buy longer aluminum extrusions, belt and wire separately. Extra parts should cost <$50, nowhere near the hundreds of dollars that sellers are asking for size difference. This is a bit trickier if the machine has linear rails instead of V-wheels. Similar pricing logic applies to the different sizes of machines in "Modern pen plotters" category but you can't as easily extend them, because they might be using less common type of aluminum extrusions which will be much harder to source on your own. One more thing to keep in mind is that you can't extend it infinitely this way, at certain size it will become unreliable and require different hardware design or at least beefier components motors, rails, motor driver.
62 |
63 | The ones costing $100-$150 aren't a bad deal, if you tried to source exactly the same parts yourself it's not hard to end up with slightly higher cost especially considering shipping cost when ordering from multiple vendors.
64 |
65 | Cheap price comes with it's downsides (which might not be a problem depending on your skill set).
66 |
67 | There is a bit of lottery factor with these sellers. Not so much that you won't receive anything at all, but you might not receive exactly the same thing as in pictures.
68 |
69 | Related problem with cheap kits consisting almost purely from off the shelf components is that sellers might be substituting parts without ever testing whether all the parts fit together. Stuff like swapping a buttonhead screw (flatter and wider) with one that has cylindrical socket head (taller and narrower), replacing countersunk with non countersunk, changing the belts to slightly wider or narrower ones, replacing motors with ones that have wires attached on different sides, replacing 16teeth pulleys with 20teeth, different type of mounting brackets and so on.
70 | Small changes like that might cause parts to interfere during assembly. Or seller might forget to substitute all the related parts. In a well designed machine unless it something very compact, changes like that are usually fine. You wouldn't normally design everything with tightest fit possible places as that not only makes part substitution but also accounts for variance within same part and also makes assembly process easier. Good sellers would test such things, but you can't expect the same from sellers who can't even be bothered to make their own pictures or write description for store listing.
71 |
72 | Don't expect high quality, accurate instructions and be ready to figure out things yourself.
73 |
74 | One more potential upgrade for these is replacing the controller board. Many of these plotters use same controller board as axidraw to allow using with axidraw software. It's a <10years old board with underpowered microcontroller and custom protocol supported supported almost exclusively by axidraw sofware. See [Diy plotters](./diy-plotters.md) for alternative choices. You can now get much more powerful controller boards, with better feature set and supported by wider set of software for 1/3 the price of EBB board.
75 |
76 | Related category of machines is cheap non enclosed laser engravers, sometimes also sold as laser engravers/plotters. The movement part of these are very similar to previous, but maybe slightly higher quality with more custom parts. Makes sense since the laser engraves have significantly bigger market for making customized gifts and merchandise and wooden trinkets, and it's not something which can be easily substituted by other technique.
77 | My recommendation is stay away from these or at least immediately throw the laser module part into a bin. They are recipe for permanent eye damage to you and everyone around you. And you need proper ventilation. Laser cutters are not something to be used in your living room with children or pets running around.
78 | From the perspective of modifying one for pen plotting, a lot these have X axis high above desk surface. This is both due to height of laser module and also to support engraving various physical objects not just sheet material. It leads to significant stickout for the z axis and tool, which is fine for a laser engraver that has no side loads, but not optimal for pen plotting. You want the pen to be held as low as possible to minimize deflection.
79 |
80 | * DBU21
81 | * ly drawbot
82 |
83 | ## DIY builds
84 | For more information read [DIY plotters](./diy_plotters.md)
85 |
86 | DIY builds is the category which can vary the most. You can make something very cheap, or you can make something with decent performance which compares to modern pen plotters at half the price.
87 |
88 | The existing ecosystems of DIY CNC machines and more lately 3d printers means that there is wide availability of mechanical parts, electronic parts, controller boards and software.
89 |
90 | Some of the cheapest builds will likely be wallbot/polargraph style or hobby servo based scara type.
91 |
92 |
93 |
94 | ## Tabletop hobby plotters/vinyl cutters
95 | Compared to alternatives small format vinyl cutters meant for crafts and arts can be cheap option. These type of machines are meant not just for vinyl-cutting but also various crafts and arts projects like various paper crafts, making fancy greeting cards, scrapbooking, lightweight cloth cutting for quilting.
96 |
97 | Price is in $200-$400 range.
98 |
99 | Most common brands are Silhouette with their Cameo series, Brother with ScanNCut and Cricut.
100 |
101 | Software is one of the strongest and weakest parts of these machines. One hand it they provide high quality easy to use software, which comes with presets for the various tools and materials. On the other hand all 3 manufacturers try to steer you towards their subscription service. With some of functionality arbitrary locked away behind higher subscription tiers. In some of the cases even basic functionality like "upload your own design" is considered premium feature. Before buying do a proper reasearch and consider if you are fine with the business practices of specific manufactuer.
102 |
103 | In terms of versatility while they can partially limit your paper and pen choices that is somewhat compensated by being able to do various non drawing projects. They are also designed to be used with cutting mats and potentially thick materials, so while they are roller based, paper limitations aren't as bad as other roller based machines.
104 |
105 | ## Vinyl cutters
106 | Commercial larger format vinyl cutter from well known brands like Roland or Graphtec can be quite pricey up to few thousands. But there are also some options from less known Chinese brands like Vevor which have models in $300-$1000 range.
107 |
108 | Almost all the vinyl cutters are using roller system. This and all it's associated problems is one of the biggest downside using one as a pen plotter.
109 |
110 |
111 | ## Pen attachment to for your existing CNC device
112 | If you already have some kind of computer controlled device like a CNC router or a 3d printer, you can make a pen attachment for it.
113 | And since you have it means you already have the tool for creating the attachment.
114 |
115 | Don't forget that the pen mount needs to be spring loaded (rubber bands can be used as well), so that you can get reliable pen pressure without worrying about surface not being perfectly flat. See the [Z axis](#z-axis) section for more details. If you ignore this something will bend anyways, either the pen or frame of your device. The bed of some 3d printers is mounted on springs, don't rely on those for this purpose. They are very stiff and preloaded, compressing them even by fraction of millimeter will take way more force than you should use with a pen.
116 |
117 | The downside to this approach is that Z axis in most 3d printers isn't very fast, since during normal usage there is barely any Z movement. It's not problem for small simple drawings, but for larger ones with more than 10k-100k pen lifts this can be a major bottleneck. If you finetune everything so that you only need to lift the pen <1mm, it might not be so bad, but that will be hard to combine with reliable pen pressure.
118 |
119 | You can find existing models designed specifically for many of the most popular 3d printers https://www.printables.com/@Kabacis_332837/collections/1870430 .
120 |
121 | # Pen plotter types
122 |
123 |
124 | ## Standard Cartesian build
125 | The most straight forward thing to have is having X,Y,Z axis perpendicular to each other, and each controlled by their own stepper motors. The classic approach is having all 3 axis stacked serially in the order Y, X, Z.
126 |
127 | There are other common axis setups used by different kind of CNC machines, but they make less sense for pen plotters.
128 |
129 | Since the X axis mounted on top of Y there needs to be way to move both ends of X axis. Pushing just one of them would likely result in skewing or jamming. One solution is just having 2 motors for Y axis, that's what many CNC routers for cutting sheet material do. Otherwise you need to somehow synchronize the 2 sides of Y axis. Many of the cheap non enclosed laser cutters, use a rotating metal rod for connecting the belt on two sides.
130 |
131 |
132 | Downsides:
133 | * two sided Y axis increase total part count and the mechanical complexity
134 | * X axis motor rides along the Y axis thus increasing moving weight and limiting acceleration
135 |
136 | ## H-bot
137 | (See [T-bot](#t-bot) as simpler version of this if you want to understand how this work)
138 |
139 | H-bot has it's name from the shape of it's belt path. The frame also has H shape, but not every ploter with H shape is H-bot. Instead of having separate motors controlling each axis, there two motors connected to single loop of belt. Both motors are responsible for X and Y movement. Depending on whether they are spinning in same or opposite directions you will get the movement along either X or Y axis. Spinning just one them will result in diagonal movement. While this might sound complicated all decent controller firmwares should have a builtin mode for this type of kinematics, so you don't need to worry too much about it.
140 |
141 | Downsides:
142 | * belt path introduces twisting force for the x axis
143 | * single very long belt loop
144 |
145 |
146 | Benefits:
147 | * X and Y motors are mounted in fixed position, they don't move along axis, thus decreasing movable weight
148 |
149 |
150 | ## Core-xy
151 | One of recent trends among 3d printer builds is having core-xy kinematics. It shares many of the properties with H-bot, but solves some of it's downsides at the cost of slight increase in complexity.
152 |
153 | Note that there is large amount of seriously flawed core-xy designs out there. Before designing your own, or making someone's else design I would recommend reading some articles so that you are aware of potential pitfalls and how to avoid them.
154 |
155 |
156 | Benefits:
157 | * fixed motor mounts -> less moving weight thus better acceleration and speed
158 | * slightly shorter belt paths compared to H-bot
159 |
160 | Downsides:
161 | * more complex belt path
162 |
163 | Misc posts:
164 |
165 | * https://drmrehorst.blogspot.com/2018/08/corexy-mechanism-layout-and-belt.html
166 | * http://www.corexy.com/theory.html
167 |
168 |
169 | ## T-bot
170 | T-bot consists of two straight pieces connected in a cross or T shape. Similar to H-bot the T-bot has single belt connected to two motors and moving in X or Y direction requires turning both motors at the same time.
171 |
172 | Due to simple and cheap design this is common design used both by commercial machines like Axidraw, cheap DIY kits, and also various DIY builds.
173 |
174 |
175 | Benefits:
176 | * small part count -> cheap
177 | * fixed motor mounts -> less moving weight
178 | * While not being used, doesn't take too much space
179 |
180 | Downsides:
181 | * Takes alot ot space while being used. Working area is less than half of space taken by machine while active. Can't be placed next to a wall.
182 | * Cantilever design causes a lot of force in the central connection, can result in unsupported end drooping and variance in vertical position depending on X position.
183 |
184 |
185 | * https://www.youtube.com/watch?v=Ww2grGsl3Dk (video explaining how T-bot works)
186 |
187 |
188 | ## Roller based plotters
189 | Roller based plotters move the paper along Y axis using rollers. This has an advantage of being more compact and avoid the need for Y axis to move whole X axis assembly thus resulting in overall lighter and simpler design.
190 | This is an approach used by many of vintage plotters and modern vinyl cutters. This design also allows handling rolls of paper, which can be more convenient and cheaper to handle compared to individual paper sheets.
191 |
192 | But not all roller based plotters support paper in in rolls, some plotter models have variants with and without paper roll support.
193 |
194 | Not all roller based plotters fully utilize the space saving benefits of roller system. HP 7470A has a shelf for the paper end in front and back of roller system, making the plotter depth almost as big as the paper length it's using.
195 |
196 | Also be aware that many roller based devices support only very specifc paper widths due to limited positions of top and bottom rollers.
197 |
198 | Roller based design is less common for DIY machines, as it's tricky to get it working right and reliably especially for bigger paper sizes. Something like A4 is not so bad. Even commercial machines occasionaly have notes like about position not being reliable for plots longer than 1-2m assuming it's even supported. I don't recommend trying to make a roller based machine, unless you are up for a serious challange and are more interested in mechanical tinkering than getting a functioning pen plotter at the end.
199 |
200 | Many of the DIY roller plotters are either inspired or directly based on design done by "IV projects".
201 |
202 | * https://www.youtube.com/watch?v=wX90X4rVUr8
203 | * https://www.youtube.com/watch?v=DeLeu5LkZCo
204 | * https://github.com/IVProjects/Engineering_Projects/tree/main/ProjectFiles/Pen%20PlotterV2
205 | * https://github.com/IVProjects/Engineering_Projects/tree/main/ProjectFiles/High-Speed%20Pen%20Plotter
206 | * https://www.thingiverse.com/thing:3789969
207 | * https://www.youtube.com/watch?v=AuwU73lvwYM
208 |
209 |
210 | * https://github.com/BenjaminPoilve/Liplo
211 |
212 | ## Wallbot/polargraph/ ...
213 |
214 | This style of machine consists, of main pen hanging on string/chain between two motors.
215 |
216 | This type of plotter can be very cheap, for the simplest version you need:
217 | * 2 stepper motors
218 | * controller board
219 | * 1 hobby servo
220 | * wires somewhat long
221 | * string
222 | * power supply
223 | * means to mount it all on a wall or maybe a whiteboard
224 | Everything else (which isn't a lot) can be 3d printer, made from junk or any other material you are comfortable working with.
225 |
226 | It is also one of the simplest ways for very large plots.
227 |
228 | The precision and speed will likely not be very good.
229 |
230 | * [Polargrpah](https://www.instructables.com/Polargraph-Drawing-Machine/)
231 | * [Hetor](https://juerglehni.com/works/hektor)
232 | * [Makelangelo](http://www.makelangelo.com/)
233 |
234 | ## SCARA/5-bar linkage
235 | Technically SCARA and 5-bar linkage mean slightly different things, but many of the plotters discussed are both, so it helps searching if you try both names. A serial SCARA robot wouldn't be using a 5-bar linkage.
236 |
237 | In theory SCARA robots can be very fast, and have relatively large working area which is bigger than their footprint. The main industrial application is picking up and moving around small parts, similar to delta robots.
238 |
239 | The potential for speed comes from lightweight arms and having all actuators being placed in main pillar and not having to move around.
240 |
241 | In practice most pen plotters using this type of mechanism are very slow, with small working area and quite imprecise.
242 |
243 | Most common categories are either toy robots described in [Toy plotters](#toy-plotters) section, or DIY builds also using 2-3 hobby servos. This is one of the cheapest/simplest pen plotters you can make. In the most minimal case you need
244 | * 2-3 hobby-servos
245 | * any microcontroller board
246 | * power source
247 |
248 | The arms can be built from any junk, it's not going to be precise or very fast anyway. These types of cheap plotters DIY plotters are more of robotics learning projects with the build process and programming them being more important than using final result as practical pen plotter. This means that use of a well known CNC controller firmware is less useful allowing to use almost any microcontroller instead of purpose built 3d printer or CNC controller board. Another simplification comes from using only hobby servos which thus removing need for stepper motor drivers.
249 |
250 | It is possible to make less floppy and fast SCARA plotter, and you can find some DIY projects doing that. Although those are mostly non plotter robot arms used as medium/high complexity robotics learning exercise. A high performance SCARA arm will likely need somewhat beefy mechanical design and powerful motors.
251 |
252 | The lack of precision comes in typical DIY builds comes from multiple factors:
253 | * Extended arms have a lot of leverage on the joints which makes everything flex a lot more than comparable Cartesian design
254 | * A hobby servo will likely have no more than 10-14bits for full motion range of ~90-180°. A stepper motor without microstepping has 200steps (<8bits) for 360° and microsteps might add up to 8 more bits. Any easily accessible angle sensor will also likely have no more than 10-14bits of resolution. By very rough estimates with 5 cm arms that gives ~0.1mm resolution which doesn't sound so bad. But as the area increases angle accuracy doesn't improve. All the movement range comes from angle accuracy of less than single motor turn. In most other robot designs single motor turn is responsible for a small range of motion, and for longer moves you perform multiple turns of motor. For comparison typical Cartesian design with stepper motors will likely have resolution of 0.16-0.2mm without microstepping, once you add microstepping you get resolution of 0.0008-0.0125mm and it isn't affect by working area size.
255 | * One more source of bad precision and jerky movement comes from the math required to transform the x y coordinates to motor angles. It requires moderate moderate amount of trigonometric calculations. Even worse you can't just calculate angles for endpoints of movement and linearly interpolate between the two, you need to do full calculations for all the intermediate points. Doing this thousands of times per second on a microcontroller which might not even a have a floating point unit can be a problem.
256 |
257 |
258 | Some examples
259 | * https://www.brachiograph.art/
260 | * https://www.youtube.com/watch?v=a46DMy_3xc4
261 | * [Mechpen](https://tinkerlog.com/2019/08/27/mechpen/) (large one)
262 |
263 | ## Uncommon designs
264 |
265 | * https://github.com/bdring/Polar-Coaster
266 |
267 | ### Rolling plotter
268 |
269 | * https://builds.openbuilds.com/builds/a-rolling-plotter.9207/
270 |
271 | # Z axis
272 | Requirements of pen plotters compared to other CNC machines have some unique challenges, but it also opens doors for solutions which wouldn't be suitable in other devices.
273 |
274 | Pen plotters don't really need arbitrary z axis movement. It's only necessary to lower the pen so that it touches paper and lifting it above paper.
275 |
276 |
277 |
278 | ## RC servo
279 |
280 | One of the cheapest and simplest option is using a RC servo.
281 |
282 | Good parts:
283 | * doesn't need a separate motor driver
284 | * doesn't need homing
285 | * (smaller ones) can be very light
286 |
287 | Downsides:
288 | * Limited motion range
289 | * Cheaper ones will wear out after a while
290 | * Noisy and not the fastest
291 |
292 | ## Solenoid
293 |
294 | Good parts:
295 | * very fast (up to 10 dots per second or better)
296 |
297 | Downsides:
298 | * noisy
299 | * very limited motion range (1-3mm)
300 |
301 | Note that while the theoretical movement range of many solenoids might be 10-20mm, the force drastically falls outside the sweet spot. A solenoid might have >500g of force at one end of movement, but after just 1mm of travel it will likely be halved, with next mm halving it again. On the other end of 10mm travel you might get less than 5g of force barely enough to overcome the return spring.
302 |
303 | So if you design a z axis expecting 20mm of travel from solenoid, it will likely be way too strong and weak at the same time.
304 |
305 | ## Stepper belt ring
306 | An interesting approach using a stepper motor for Z axis is used by [LumenPnP](https://www.opulo.io/products/lumenpnp) machine. A single vertically mounted belt loop with 2 toolheads attached, one on each side. This gives movement of 2 tools for the cost 1 stepper motor.
307 |
308 | Software and firmware setup could require more customization than usual since both extremes of the axis cause one of the two tools to be activated.
309 |
310 | 
311 |
312 | ## String/Stepper belt pulling up
313 | A string or a belt can only apply force in tension, it can't push things. Usually that's a limitation, but in this case it's a feature. Belt can be used to pull the pen up, while leaving downward motion to gravity or a spring.
314 |
315 | Unlike the stepper belt ring approach, this doesn't need a belt tensioning mechanism.
316 |
317 | A slightly more complicated version of this can be seen in UUNA TEK iDraw machines.
318 |
319 | 
320 |
321 | ## Stepper with rack/pinion on single rail
322 | Somewhat unique plotter Z axis design can be seen in UUNA TEK 3 devices. Vertical motion is achieved using rack and pinion. It uses a clever solution for dealing with double slide problem by having two carriages on the same linear rail.
323 | Rack and pinion mechanism lifts the silver color metal plate. But the pen holder (red) is using separate carriage isn't directly connected to the plate. Lifting the plate also lifts the pen holder, but due to the shape of hole lowering the plate doesn't push the pen holder down.
324 |
325 | 
326 |
327 | * https://www.printables.com/model/868919-generative-pen-plotter-art-cnc-arduino-vinyl-cutte
328 |
329 | ## (not recommended) Lead screw
330 | Many DIY CNC machines use some kind of lead screw mechanism for lifting and lowering Z axis.
331 |
332 | That makes sense for CNC routers where you might be lifting a spindle which weights a few kg, or 3d printers lifting whole X axis assembly or the printbead. It makes less sense for pen plotters.
333 |
334 | Leadscrew does 2 things it converts rotational movement into linear motion and it provides a force/distance trade off. It also provides a simple mapping from the motor angle to vertical distance, something like 1 turn or 1 stepper step being equal to x mm of vertical travel.
335 | In some cases you can't even backdrive the leadscrew based Z axis thus which prevents it from falling down when motors are turned off. In pen plotters you want the opposite -> force requirements are minimal and you want to move it as fast as possible. It is also not necessary to have control over exact Z position.
336 |
337 | Any leadscrew based design will also likely need secondary sliding mechanism for ensuring consistent pen pressure without crushing the pen.
338 |
339 | ## Tilting
340 | Instead of having some kind of vertical linear rails, which requires some less common components. It is sufficient to have simple tilting mechanism requiring at most regular ball bearings, but a smooth metal pin against plastic should also work.
341 |
342 | Downside to this approach is limited movement range and pen tilting as gets lifted. If everything is well designed it's not a problem.
343 |
344 | ## Side mounted actuator
345 | Instead of having Z axis actuator move along X axis, it can be mounted at the end of X axis. In this setup it lifts or twists a long bar which in turn lifts or lowers the pen.
346 |
347 | This is the approach used by many medium and small size vintage pen plotters, for example HP 7475A.
348 | The actuator which you mount on the side can be anything: solenoid, stepper motor, hobby servo. Most of the vintage plotters used solenoids for their fast movement, but many newer DIY designs choose steppers or hobby servos as there are more examples of using them in DIY CNC machines.
349 |
350 | Getting this right and functioning takes more upfront engineering effort taking into account positioning, movement range and forces of each component.
351 |
352 | Not strictly required but this approach is occasionally combined with one more trick -> reusing the X axis linear bearing for tilting the pen holder. The trick is best best illustrated by this DIY build from IV Project https://www.youtube.com/watch?v=wX90X4rVUr8 .
353 |
354 | 
355 |
356 | Benefits:
357 | * very lightweight tool head
358 | * allows using powerful actuator with no weight penalty
359 | * toolhead can be fully passive (no electronics or wires attached)
360 |
361 | Downsides:
362 | * small Z axis movement range
363 |
364 |
365 | # Pen changer mechanisms
366 |
367 | ## Rotary pen changer
368 |
369 | Used by many of roller based vintage plotters. Requires only single motor for spinning the carousel of pens and clever latching mechanism allowing to take and return the pen by bumping the pen holder against carousel. Usually holds ~6-8 pens.
370 |
371 | Examples: HP 7475a, HP7440a
372 |
373 | ## Linear pen changers
374 |
375 | Mostly used by flatbed vintage plotters, but there is at least one case of linear pen changer being used in roller plotter.
376 |
377 | Consists of pens being placed at the edge of drawing area and a latching mechanism similar to rotary pen changer. This allows pen changer to be fully passive without any additional actuator beside the ones used to do x/y motion.
378 |
379 | Sometimes also used by DIY machines, tricky part is having a mechanism which allows reliably grabbing and releasing the pen but holds it rigidly without wobble while drawing.
380 | Typical example - Roland DXY series.
381 |
382 | * DMP-161 - unusual case of roller plotter with linear pen changer https://www.youtube.com/watch?v=JGgGQGiP4As
383 |
384 | ## Multiple pens in tool head
385 |
386 | There are a few similar receipt printer size pen plotters using small metal capsule shaped pens. They have a rotating pen changer mechanism holding 4 pens built into the toolhead. That way there is no need to grab or release a pen during change. It only needs to rotate which was also done by bumping the mechanism against end of x axis.
387 | * https://homecomputerguy.de/en/2021/12/26/commodore-vc-1520-plotter/
--------------------------------------------------------------------------------
/notes/plotter_notes.md:
--------------------------------------------------------------------------------
1 |
2 | | model | manufacturer | type | protocols | connection | speed | max size | scale | axis | notes |
3 | | :---------- | :----------- | -------- | ------------------------------------- | --------------------------------- | --- | --------------------------------------- | ---------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
4 | | HP7221 | HP | flatbead | custom binary | RS232 serial | | | | | S and T have roller feed, C and T 8 pens |
5 | | HP7220 | HP | flatbead | HPGL | | | | | | |
6 | | HP7475A | HP | roller | HPGL | | | A3, ANSI A | 0.02488mm | XRYU(A4) / XDYR(A3) | Paper size chosen with switches in back and front. Axis direction changes depending on if it's A4 or A3 |
7 | | HP7550A | roller | HPGL | HP-IB+2xRS232 serial with passthrough | | 800mm/s, 6G | A3 | | | | paper sheet tray/feed |
8 | | HP7470A | HP | roller | HPGL | | | A4, Letter | 0.025mm | XDYR | |
9 | | HP7585B | HP | roller | HPGL | | | A4/A - A0/E 927x1190mm | 0.025mm | | |
10 | | DMP-40V | HI | roller | DMPL | | | 400-420mmx2000mm | 0.1mm, 0.001in, 0.005in | | Has motorized blade rotation |
11 | | DMP-61 | HI | roller | DMPL,HPGL | | | A-D,A4-A1 | 0.001in 0.005in 0.1mm 0.025mm | related to small/large chart option | |
12 | | DMP-62 | HI | roller | DMPL,HPGL | | | A-F,A4-A0,B1 | 0.001in 0.005in 0.1mm 0.025mm | varies | Axis direction depends on small chart/large chart option. Origin and axis direction in HPGL mode differs from DMPL. HPGL origin in center. |
13 | | DMP-161 | HI | roller | DMPL,HPGL,HP-GL/2 | | | <=24in (specific widths) | 0.001in 0.005in 0.1mm 0.025mm | varies | axis direction varies depending on size, but might be possible to configure fixed corner. |
14 | | DMP-162 | HI | | DMPL,HPGL,HP-GL/2 | | | 36in | | varies | |
15 | | DMP-162R | HI | | DMPL,HPGL,HP-GL/2 | | | 36in +rolls | | varies | Supports paper rolls. |
16 | | DXY-1350A | Roland | flatbead | RD-GL II, RD-GL I,DXY-GL | parallel(centronics)+serial(db25) | 600mm/s | | | | Electrostatic paper holder+replot Otherwise same as 1150A. |
17 | | DXY-1150A | Roland | flatbead | RD-GL II, RD-GL I,DXY-GL | parallel(centronics)+serial(db25) | 600mm/s | A3,B,431.8x297mm | 0.025mm,0.1mm | TODO, centered 0 in RD-GL II mode | Magnetic paper holder. round buttons, holes for pen storage |
18 | | DXY-1350 | Roland | flatbead | | | | | | | round buttons, holes for pen storage, electrostatic holder, 7segment position indicator, replot |
19 | | DXY-1250 | Roland | flatbead | | | | | | | round buttons, holes for pen storage, electrostatic holder, 7segment position indicator |
20 | | DXY-1150 | Roland | flatbead | | | | | | | round buttons, holes for pen storage |
21 | | DXY-1300 | Roland | flatbead | RD-GL I, DXG-GL | parallel(centronics)+serial(db25) | | | DXY-GL(0.025mm, 0.1mm), RD-GL I(0.025mm) | XRYU | square buttons, electrostatic holder, 7segment position indicator, replot |
22 | | DXY-1200 | Roland | flatbead | RD-GL I, DXG-GL | parallel(centronics)+serial(db25) | | | DXY-GL(0.025mm, 0.1mm), RD-GL I(0.025mm) | XRYU | square buttons, electrostatic holder, 7segment position indicator |
23 | | DXY-1100 | Roland | flatbead | RD-GL I, DXG-GL | parallel(centronics)+serial(db25) | | | DXY-GL(0.025mm, 0.1mm), RD-GL I(0.025mm) | XRYU | square buttons, magnetic holder |
24 | | DXY-980A| Roland | flatbead | | | | | | | Electrostatic holder, 7segment XY position indicator
25 | | DXY-880A | Roland | flatbead | | | | | | | Magnetic holder |
26 | | DXY-880 | Roland | flatbead | DXY-GL,RD_GL | parallel(centronics)+serial(db25) | | A3 (with unreachable padding),380x270mm | 0.1mm DXY, 0.025mm RD-GL | XRYU | Magnetic holder |
27 | | DXY-980 | Roland | flatbead | DXY-GL,RD_GL | parallel(centronics)+serial(db25) | | A3 (with unreachable padding),380x270mm | 1) 0.1mm DXY, 0.025mm RD-GL | XRYU | Electrostatic holder, 7segment XY position indicator |
28 | | DXY-990 | Roland | flatbead | RD-GL I | parallel(centronics)+serial(db25) | 300mm/s | A3, B (unreachable padding) | | | electrostatic+7segment position+pen buttons |
29 | | DXY-885 | Roland | flatbead | RD-GL I | parallel(centronics)+serial(db25) | 300mm/s | 416mmx259mm (ANSI B), 403mmx276mm (A3) | | | magnetic
30 | | DXY-800 | Roland | flatbead | DXY-GL | parallel(centronics)+serial(db25) | 180mm/s | 350x260mm | 0.1mm | | 8 pens |
31 | | DXY-101 | Roland | flatbead | DXY-GL | parallel(centronics)+serial(db25) | 180mm/s | 370x260mm | 0.1mm | | 1 pen |
32 |
33 | 1) need to verify
--------------------------------------------------------------------------------
/notes/protocols.md:
--------------------------------------------------------------------------------
1 |
2 | | | HP-GL | GP-GL | DMP/PL | DXG-GL, CAMM-GL mode 1 | RD-GL, CAMM-GL mode 2 | GCode |
3 | | :------------------- | :----------- | -------------- | ----------------------------------------------- | --------------------------- | --------------------- | ------------------------ |
4 | | Main or initial user | HP | Graphtec | Houston instrument | Roland | Roland | |
5 | | units | 0.025mm, 0.02488mm* | 0.1mm/0.025mm | EC1 0.001in, EC5 0.005in, ECM 0.1mm, ECN 0.025mm | 0.025mm, some mills 0.01mm, 0.1mm | 0.025mm | G20 inch, G21 metric(mm) |
6 | | pen lift/down | PU/PD | M/D | M/D | M/D | PU/PD | machine specific |
7 | | absolute/relative | PA/PR | M/O (down D/E) | A/R | M/R (down D/I) | PA/PR | G90/G91 |
8 |
9 |
10 | # HP-GL (and HP-GL/2)
11 |
12 | Some materials mention HP-GL/2 and HP RTL, what are those?
13 |
14 | HP RTL is protocol for raster printers, not relevant for pen plotters
15 | The HP-GL/2 looks very similar to HP-GL, but it seemed to be described in context of device that support raster printing and other printing protocols. It's unclear if
16 |
17 | Exact scaling factor HP-GL devices is unclear. Many manuals say simply 0.025mm, some device manuals say "0.02488mm or 0.00098in", but there are also some that say "0.00098in 0.025mm". Does the real value vary between device models, are some of those simply inacurate rounding? It almost sounds like 0.02488mm is bad double conversation roundtrip. And that's just the HP docs, who knows what the other manufacturers implementing HP-GL do.
18 |
19 | * 0.025mm = 40steps/mm = 1016steps/in (exact) ~= 0.00098425197in | 100%
20 | * 0.00098in=0.024892mm ~= 1020.408163 step/in ~= 40.173549 step/mm | 99.6%
21 | * 1021step/in ~= 0.0009794319in ~= 0.024877571mm | 99.5%
22 |
23 | Rounding error between 0.02488 and 0.025 might seem insignificant, but that's 1.5mm for A4 page or 3mm for A3 which can be easily measured and seen with naked eye.
24 |
25 |
26 | ## Available references
27 | * HP DraftPro Plotter Programmer's Reference
28 | * CHAPTER 9 HP-GL Graphics Language - not the offcial docs from HP
29 | * The HP-GL/2 and HP RTL Reference Guide A Handbook for Program Developers
30 |
31 | ## Secondary references (for confirming dialects supported by other manufacturer devices)
32 | * DMP-60 SERIES PLOTTERS OPERATION MANUAL
33 | * Houston Instrument DMP-160 Series Plotters Operation
34 | * Various Roland manuals where one of the supported modes is renamed version of HP-GL
35 |
36 |
37 | # GP-GL
38 | * Graphtec MP4000 Series command set reference manual
39 | * https://github.com/fablabnbg/inkscape-silhouette/blob/main/Commands.md
40 | * https://www.ohthehugemanatee.net/2011/07/gpgl-reference-courtesy-of-graphtec/
41 |
42 | # Roland CAMM-GL (I/II/III), DXG-GL, RD-GL (I, II, III)
43 |
44 | The versioning is very weird. According to CAMM-GL II programmer's manual:
45 | > Consideration has been made for to ensure compatibility with DXY-GL for plotters from
46 | Roland DG Corp. and with CAMM-GL III for the CAMM-1 Series of cutting machines
47 | (mode1), as well as with CAMM-GL I for the CAMM-3 Series of compact modeling
48 | machines (mode1).
49 |
50 | Many Roland plotters support two command modes, one slightly similar to GP-Gl and other quite similar to HP-GL.
51 |
52 |
53 | | name | device series | similar roland protocol | similar protocol | device type | notes |
54 | | :----------------- | :------------ | :---------------------- | :--------------- | :-------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
55 | | DXG-GL | DXY | | GP-GL* | pen plotter | *many of the more advanced commands differ from GP-GL |
56 | | RD-GL I, II, III | DXY,DPX | | HP-GL | pen plotter | Roman number roughly means protocol version, with higher version meaning more commands. But III isn't a strict superset, some commands are removed or argument meaning changed. |
57 | | CAMM-GL III mode 1 | CAMM-1 | DXG-GL | GP-GL* | cutting plotter | |
58 | | CAMM-GL II mode 1 | CAMM-2 | DXG-GL | GP-GL* | engraver | Additional commands for spindle motor control and engraving depth |
59 | | CAMM-GL I mode 1 | CAMM-3 | DXG-GL | GP-GL* | mill | Adds additional commands for 3axis movement and spindle control. Some mills are using 0.01 instead of 0.025 step size. Recommended to use CAM software meant for CNC mills instead of plotters/engravers. |
60 | | CAMM-GL III mode 2 | CAMM-1 | RD-GL | HP-GL | cutting plotter | The Roman number based numbering scheme for RD-GL and CAMM-GL has completely different meaning, |
61 | | CAMM-GL II mode 2 | CAMM-2 | RD-GL | HP-GL | engraver | |
62 | | CAMM-GL I mode 2 | CAMM-3 | RD-GL | HP-GL | mill | Recommended to use CAM software meant for CNC mills instead of plotters/engravers. |
63 |
64 | DXG-GL, CAMM-GL mode 1 uses only 1 character commands while the GP-GL has some 2 character commands.
65 |
66 | CAMM-GL devices have some 3 character commands prefixed by !, which can be used in both mode 1 and mode 2. These are usually Roland specific config commands which differ from GP-GL and HP-GL.
67 |
68 |
69 | ## Available references
70 | * CAMM-GL II Programmer's Manual (CAMM-GL II mode 1, mode 2)
71 |
72 | * DXY-880 operation manual (DXG-GL, RD-GL)
73 | * DXY-1350A manual (DXG-GL)
74 |
75 |
76 | # DM/PL
77 |
78 | ## Available references
79 | * DMP/PL COMMAND LANGUAGE
80 | * Houston Instrument DMP-160 Series Plotters Operation Manual
81 | * HIPLOT® DMP-51/52 OPERATION MANUAL
82 | * DMP-60 SERIES PLOTTERS OPERATION MANUAL
83 |
84 | # GCode
85 | Commonly used CNC mills, lathes, routers more recently also used by most FDM 3d printers. Popular choice for DIY machines with wide variety of available controller boards and firmwares.
86 |
87 | While basic commands are similar almost major manufacturer or firmware uses their own dialect. The biggest differences are usually related to:
88 | * initialization
89 | * homing procedure
90 | * device configuration changes
91 | * machine type and tool specific actions (needs of CNC mill are different from a lathe or 3d printer). For example 3d printer will have commands for controlling hotend temperature and synchronizing filament flow with movements, but CNC mills are more concerned with how fast the tool spins, tool size compensation and various routines for special operations like drilling or tapping.
92 | * macros and builtin scripting functionality
93 |
94 | ## Available references
95 | When possible check the documentation of relevant controller manufacturer or firmware.
96 |
97 | * https://www.linuxcnc.org/documents/ the GCode dialect is based on RS274/NGC . LinuxCNC rarely used for pen plotters
98 | * RS274/NGC - not to be confused with various RS274 standards, describes the NIST reference GCode interpreters (with actual source code not an abstract specification)
99 | * RS274 - common name for various standards made by NIST and other standards organizations describing the GCode. As far as I am aware the text can be only obtained by paying like many other standards. Limited relevance for hobbyists since most controller firmwares follow it very loosely.
100 | * https://reprap.org/wiki/G-code - covers differences between various 3d printer firmwares
101 | * https://github.com/gnea/grbl/wiki and https://github.com/gnea/grbl/wiki While the original GRBL itself isn't actively maintained and the supported hardware is outdated, there are many forks derived from GRBL supporting newer hardware which are using similar gcode dialect. There are also plenty of older (and not so old) DIY builds still using it.
102 | - [FluidNC](http://wiki.fluidnc.com/) - popular for DIY plotters, currently supports only controller boards using one specific ESP32 chip, but range of supported hardware configurations isn't bad
103 | - [grblHAL](https://github.com/grblHAL)
104 | - [RabbitGRBL](https://github.com/SourceRabbit/RabbitGRBL)
105 | - [uCNC](https://github.com/Paciente8159/uCNC)
106 | * [MarlinFW](https://marlinfw.org/meta/gcode/) - Popular open source controller firmware. Supports wide range of controller boards. Primary targeted at 3d printers, but also has some CNC and laser specific features.
107 |
108 | ## Other DIY friendly GCode interpreters
109 | * [Klipper](https://www.klipper3d.org/G-Codes.html) - high performance gcode interpreter. Primarily targeted at 3d printers, non 3d printer functionality limited. Good support for wide range
110 |
111 | # EBB board protocol
112 |
113 | Used by AxiDraw and iDraw machines.
114 |
115 | * http://evil-mad.github.io/EggBot/ebb.html
116 |
117 | ## Available references
118 | * [EBBB command set Firmware V3.0+](http://evil-mad.github.io/EggBot/ebb.html)
--------------------------------------------------------------------------------
/notes/prtocols_big.csv:
--------------------------------------------------------------------------------
1 | HP-GL GP-GL DMP/DL DXY-GL (I) CAMM-GL II mode1 CAM-GL I mode 1 RD-GL I RD-GL II RD-GL III CAMM-GL II mode2
2 | Main manufacturer HP Graphtec Houston instrument Roland Roland Roland
3 | Known plotters MP4000 DXY-1350A, DXY-1150A,DXY-880 PNC-3100 DXY-1350A, DXY-1150A DXY-1350A, DXY-1150A, DPX-3700A, DPX-2700A DPX-3700A,DPX-2700A
4 | Reference material Chapter 9 HP-Gl CAMM-GL II programmer’s manual CAMM-GL II programmer’s manual
5 | Based on GP-GL GP-GL GP-GL HP-GL HP-GL HP-GL RDL-GL I, CAMM-GL III mode 2, CAMM-GL I
6 | Some compatibility DXY-GL, CAMM-GL III mode 1, CAMM-GL mode 1 DXY-GL, CAMM-GL III mode 1, CAMM-GL mode 1
7 | Notes Has some engraving sturctions CNC mill, 3axis and spindle Accepts fractions Most (maybe) parameters accept only integers, has a few more commands than RD-GL I, symetric coordinates configurable 0, 0 always in bottom left unlike
8 | Command separator/terminator ; ETX \r\n ; ; ;
9 | ---------------------------- Basic movement --------------------------------------------------------------------------------------
10 | Move/Pen up PU x1,y1,...; M x1, y1, ... M x1, y1, ... M x1, y1, ... PU x1,y1,...; PU x1,y1,...; PU x1,y1,...; PU x1,y1,...;
11 | Relative move PU/PR O dx,dy R dx1, dy1 R dx1, dy1 PU/PR PU/PR PU/PR PU/PR
12 | Draw absolute PA/PD D x1, y1, ... D x1, y1, ... D x1, y1, ... PA/PD PA/PD PA/PD PA/PD
13 | Relative draw PR/PD x1,y1,...; E dx1,dy1, ... I dx1,dy1, ... I dx1,dy1, ... PR/PD x1,y1,...; PR/PD x1,y1,...; PR/PD x1,y1,...; PR/PD x1,y1,...;
14 | Move polar MP r,o,[t]
15 | Draw polar DP r1,o1,r2,o2,rn,on
16 | Relative draw polar EP
17 | Relative move polar OP
18 | Radius plot RP
19 | ??? PE
20 | Advance full page (ignored)AF; (ignored)AF;
21 | Page feed PG[ n]; PG[ n]; PG[ n]; PG[ n];
22 | ---------------------------- Circle stuff --------------------------------------------------------------------------------------
23 | Circle center A x,y A x,y
24 | Circle AA x,y,oc,od; W x0,y0,r1,r2,o1,o2[,d][,t] C x,y,r,o1,o2,(od) C x,y,r,o1,o2,(od) AA x,y,oc,od; AA x,y,oc,od AA x,y,oc,od; AA x,y,oc,od;
25 | Relative circle AR dx,dy,oc,od E r,o1,o2,od E r,o1,o2,od AR dx,dy,oc,od AR dx,dy,oc,od AR dx,dy,oc,od AR dx,dy,oc,od
26 | A+Circle G r,o1,o2 G r,o1,o2
27 | Circle here CI r,od ]r1,r2,o1,o2[,d][,t] CI r, od CI r,od CI r,od CI r,od
28 | ??? absolute circle stuff AT ???
29 | ??? relative circle stuff RT
30 | Sector % A+ K n,l1,l2 A+ K n,l1,l2
31 | 3 point circle WP x1,y1,x2,y2,x3,y3
32 | Ellipse )a,x0,y0,r1,r2,o1,o2,o3
33 | ---------------------------- ???????????? --------------------------------------------------------------------------------------
34 | Curve Y a,x0,y0,... Y m,x1,y1,x2,y2... Y m,x1,y1,x2,y2...
35 | Relative curve _ a,dx0,dy0,... _ m,dx1,dy1,...
36 | Bezier curve BZ a,x1,y1,x2,y3,x4,y4
37 | Axis (draw axis with tickmarks) X X p,q,r X p,q,r
38 | Tick length TL lp, ln; TL lp, ln; TL lp, ln;
39 | X tick XT; XT; XT; XT;
40 | Y tick YT; YT; YT; YT;
41 | ---------------------------- Text --------------------------------------------------------------------------------------
42 | Print text LB c1,c2,cn [terminator]; P P c1c2cn... P c1c2cn... LB c1,c2,cn [terminator] LB c1,c2,cn [terminator] LB c1,c2,cn [terminator] LB c1,c2,cn [terminator]
43 | Kana,Greek K
44 | Engraves special symbols N N n N n
45 | Alpha rotate R Q [0-3] Q [0-3]
46 | Alpha scale S S [0-127] S [0-127]
47 | ??? AD
48 | Altrnate character set CA[ n]; CA[ n]; CA[ n]; CA[ n];
49 | Standard character set CS[ n]; CS[ n]; CS[ n]; CS[ n];
50 | Activate standard character set SS; SS; SS; SS; SS;
51 | Activate alternate set SA; SA; SA; SA; SA;
52 | Move by character size CP nx,ny; CP nx,ny; CP nx,ny; CP nx,ny; CP nx,ny;
53 | Character Cord Angle (curved character quality) CC oc CC oc
54 | Font $n[,m]
55 | (unsuported)CF
56 | Absolute direction(text) DI[a,b]; DI[a,b]; DI[a,b]; DI[a,b]; DI[a,b];
57 | Relative direction(text) DR[a,b]; DR[a,b]; DR[a,b]; DR[a,b]; DR[a,b];
58 | Define label terminator DT t; DT t; DT t; DT t; DT t;
59 | DV?? (ignored)DV [0 or 1] DV path[0,1,2,3] line[0, 1]
60 | Extra text spacing Q ES w,h; ES w,h; ES w,h;
61 | ??? LO[ n]; LO[ n];
62 | ???? SD??
63 | absolute characer size SI w,h; (cm) SI w,h; SI w,h; (cm) how are fractions handled? SI w,h; SI w,h; (0.4 cm)
64 | Character slant SL[ tanO]; SL[ tanO]; SL[ tanO]; SL[ tanO]; SL[ tanO];
65 | Alpha italic I
66 | Label position LP
67 | Alpha reset A
68 | Replot character RC c,x1,y1,[P],...
69 | Symbol mode -> draws character in everyy position spciefied by PA,PR or PD until exiting symbol mode SM s; SP SM s; SM s; SM s; SM s;
70 | Relative character size SR w,h; SR w,h; SR w,h; SR w,h;
71 | ???? TD i;
72 | User defined character UC x1,y1, ...;(lift logic based on value range) (P UC c,x1,y1, ...; UC c,x1,y1, ...;
73 | Select point mark SP
74 | User’s pattern (
75 | ---------------------------- Area ,fill and polygons --------------------------------------------------------------------------------------
76 | Pen change SP n; Jn[,m] J n SP n; SP n; SP n;
77 | Line type L p L p L p LT n,l
78 | Line scale B l B l B l
79 | Hatch rectangle % (also for non rectangle) T n,x,y,d,t T n,x,y,d,t
80 | Polygon mode PM [0,1,2] PM [0, 1, 2]
81 | Shade rectangle absolute RA x,y; RA x,y; RA x,y; RA x,y; RA x,y;
82 | Shade rectangle relative RR dx,dy; RR dx,dy; RR dx,dy; RR dx,dy; RR dx,dy;
83 | Shade wedge WG r,o1,oc,od WG r,o1,oc,od WG r,o1,oc,od WG r,o1,oc,od WG r,o1,oc,od
84 | Fill type FT n[,d[,o]] FT n[,d[,o]] FT n[,d[,o]] FT n[,d[,o]] FT n[,d[,o]]
85 | ??? line,fill,limit something AC ???
86 | Line fill something LA
87 | Line type LT n[,l] LT n[,l] LT ??? LT n[,l]
88 | Pen width PW(1/300 inch) PW
89 | ??? (ignoded)RW index,width,height, pen number
90 | ??? UL
91 | ??? WU
92 | Edge rectangle absolute EA x,y; EA x,y; EA x,y; EA x,y; EA x,y;
93 | Edge rectangle relative ER dx,dy ER dx,dy ER dx,dy ER dx,dy ER dx,dy
94 | Edge wedge EW r,o1,oc,od EW r,o1,oc,od EW r,o1,oc,od EW r,o1,oc,od EW r,o1,oc,od
95 | Hatching spacing partition ratio UF d1,(d2, ...d20);
96 | Pen thickness PT[ d]; 0.1 --- 5.0(mm) PT[ d]; PT[ d]; 0.1 --- 5.0(mm) PT[ d]; (multiple of 0.4 mm)
97 | ---------------------------- Techincal --------------------------------------------------------------------------------------
98 | Initialize IN; IN; IN[ n]; IN[ n]; IN;
99 | Default settings DF; DF; DF; DF;
100 | Clear (init and reset settings) :
101 | Interface clear ;
102 | Home(go, or find) H H H
103 | ???? BP i i??
104 | CT?? CT[ n]; CT[ 0, 1];
105 | DL??? DL n,pc,x1,y1,
106 | EC?? (ignored)EC n; (ignored)EC n;
107 | ??? (ignored)FR; (ignored)FR;
108 | ??? (ignored)MC
109 | ??? (ignored)MR
110 | ??? material type? MT [0,1,2,3,4,5]
111 | Not ready??, wait for user NR; NR; NR [timeout];
112 | Activate pause unti l butto nis pressed !NR
113 | PS l,(w); PS l,w
114 | Quality level ?? QL [0..100]
115 | ??? ST [-1, 0, 1, 2]
116 | Velocity ! (multiple input modes) VS s; VS s,(n); cm/s VS [1-72] (n[1-8]) VS s;
117 | Acceleration, force *
118 | Cutter offset FC
119 | Blade rotational control FD
120 | Show message on display WD
121 | Set buffer sizes GM pl,dl,(r1,r2,r3)
122 | Buzzer/alert indicator T n
123 | Chart feed F l[t]
124 | Set terminator character =
125 | ---------------------------- Scaling and dimensions--------------------------------------------------------------------------------------
126 | Paper size PS s;
127 | Roatete coordiante system RO [0,90]; / RO [0,90]; RO [0,90]; RO [0,90, 180, 270];
128 | Scaling SC xmin,xmax,ymin,ymax SC xmin,xmax,ymin,ymax SC xmin,xmax,ymin,ymax(,type,left,bottom); SC Xmin, X,Xfactro,Ymin,Yfactor,type; SC Xmin,Xmax,Ymin,ymax,Xfactor,yFactro,tpye, left, bottom SC xmin,xmax,ymin,ymax
129 | Input mask IM[ e]; IM[ e]; IM[ e];
130 | Input p1 p2 IP p1x,p1y(p2x,p2y) IP p1x,p1y(p2x,p2y) IP p1x,p1y(p2x,p2y) IP p1x,p1y(p2x,p2y) IP p1x,p1y(p2x,p2y)
131 | Input p1 p2 relative IR p1x,p1y,p2x,p2y %
132 | Write lower left (set?) \x,y
133 | Write upper right Zx,y
134 | Input window IW Llx,Lly,Urx,Ury IW Llx,Lly,Urx,Ury IW Llx,Lly,Urx,Ury IW Llx,Lly,Urx,Ury IW Llx,Lly,Urx,Ury
135 | Clipping (blocked area) >
136 | ???? RP [1-99]
137 | Offset ↑x,y(up arrow in what encoding?)
138 | Offset polar ^P
139 | Factor &p,q,r
140 | Set origin SO n
141 | ---------------------------- State query --------------------------------------------------------------------------------------
142 | Output actual position OA; OA; OA;
143 | Output commanded position OC; OC; (unlike most other RD-GL II commands outputs fraction number) OC;
144 | GIN G
145 | call GIN C
146 | Output digitize (ignored)OD; (ignored)OD; OD;
147 | Output error OE; OE; OE; OE
148 | Output factor OF; (40 or 10 depending on 0.025mm or 0.1mm mode) OF; (->40 ) OF
149 | Output hard clip limits OH; OH; OH; OH;
150 | Output identification OI; (->1350, 1150) OI; (->1350, 1150) OI; OI;
151 | (ignored)OK;
152 | OL;
153 | Output option parameter OO; (->0,1,00,1,0,00) OO; (->0,1,00,1,0,00) OO; (->0,1,00,1,0,00)
154 | Output p1,p2 OP; OP; OP; OP;
155 | Read lower left [
156 | Read upper right U
157 | Output offset ?
158 | OT;
159 | Output status V OS; OS; OS; OS;
160 | Output status 2 @
161 | Output status 3 #
162 |
163 | Output window OW; OW; OW;
164 | Error mask “
165 | Buffer size BS s1,s2,s3,s4
166 | ---------------------------- Pallette --------------------------------------------------------------------------------------
167 | ??? (unsupported)CR
168 | ??? NP [2,4,8,16, 32]
169 | ??? (unsupported)PC
170 | ??? (unsupported)SV
171 | ??? (unsupported)TR
172 | ---------------------------- ???? --------------------------------------------------------------------------------------
173 | Call RD-GL I command ^cmd [;] ^cmd [;]
174 | AH?? (ignored)AH;
175 | Automatic pen features AP n;
176 | Text??? BL c1c2cn;
177 | CM?? CM n1, n2;
178 | Digitize clear (ignored)DC; DC;
179 | Digitize point (ignored)DP;
180 | DP??? (ignored)DP;
181 | DS?? DS s,n;
182 | EP?? EP; EP;
183 | ??? FP; FP;
184 | ??? (ignored)FS f,n;
185 | ??? something with pen groups (ignored)GP g,h,ij
186 | ??? IV s,t
187 | (ignored)KY k,f;
188 | ??? something with buffer PB;
189 | (ignored)SG[ g];
190 | motor control !MC
191 | Cutting depth, tool up position !PZ z1, c2
192 | Drill down velocity !VZ
193 | (unsupported)ESC %#A
194 | (unsupported)ESC E
195 | (unsupported)FI
196 | (unsupported)FN
197 | (unsupported)SB
198 | Control codes TODO ESC ... ESC ...
199 |
--------------------------------------------------------------------------------
/notes/random_links.md:
--------------------------------------------------------------------------------
1 |
2 | # Other collections of resources
3 |
4 | * https://github.com/beardicus/awesome-plotters
5 | * https://drawingbots.net/
6 |
7 | # Plotters:
8 |
9 | * https://www.youtube.com/watch?v=U6kt-N3fzH4
10 |
11 | # Drawings and artists:
12 |
13 | * https://github.com/LingDong- (procedural genration)
14 | * https://chocographix.net/ (vectorart)
15 |
16 | # Blogs
17 |
18 | * https://newsletter.revdancatt.com/
19 | * https://penplotter.art/
20 |
21 | # Software
22 |
23 |
24 | ## general purpose SVG editors
25 |
26 | * [Inkscape](https://inkscape.org/)
27 | * [Graphite](https://graphite.rs/) (general purpose but also supports node based workflow and even mixing them)
28 | * [BoxySVG](https://boxy-svg.com/)
29 |
30 | ## generative/node based editors
31 |
32 | * [Kinogaki](https://app.kinogaki.com/)
33 | * [Patternodes](https://www.lostminds.com/patternodes3/)
34 | * [Blender Sverchok](https://github.com/nortikin/sverchok) Blender plugin which provides functionality similar to geometry nodes
35 | * [Blender geometry nodes+Freestyle SVG exporter](https://www.blender.org/)
36 | * [Makelangelo software](https://github.com/MarginallyClever/Makelangelo-software)
37 |
38 |
39 | ## creative coding libraries/frameworks/platforms
40 |
41 | * [ln](https://github.com/fogleman/ln/tree/master) (go, 3D)
42 | * https://turtletoy.net/ (online JS)
43 | * https://processing.org/ , https://processing.org/reference/libraries/svg/index.html
44 | * [VSVG/Whiskers](https://github.com/abey79/vsvg/blob/master/crates/whiskers/README.md) (Rust)
45 | * [vpype](https://github.com/abey79/vpype) (Python, 2d drawing API + svg utilities+svg to gcode/hpgl converter)
46 | * [Urpflanze](https://urpflanze.genbs.dev/) (JS)
47 |
48 |
49 | ## Other software for plotter drawing creation
50 |
51 | A bit more flexible than single purpose plotter sketches, more niche than general purpose drawing tools.
52 |
53 | * [DrawingbotV3](https://drawingbotv3.com/) Provides of various effects for converting bitmaps to plotter friendly drawings
54 | * https://sandify.org/
55 | * https://lostminds.com/vectoraster8/
56 |
57 |
58 | ## single purpose tools/plotter sketches
59 |
60 | * https://pro.mandalagaba.com/#l5FQqM (symmetry, tiling)
61 | * https://shefalinayak.com/tile-playground/index.html (tiling)
62 | * https://isohedral.ca/other/Beyond96/ (tiling)
63 | * https://eskimoblood.github.io/elm-wallpaper-editor/ (tiling)
64 | * https://msurguy.github.io/cnc-text-tool/ (text)
65 | * https://contours.axismaps.com (maps)
66 | * https://anvaka.github.io/city-roads/ (maps)
67 | * https://github.com/anvaka/peak-map (maps)
68 | * https://plotter.vision (3d)
69 |
70 | # Misc
71 |
72 |
73 | # Blog posts
74 |
75 | * https://hannahilea.com/blog/ly-drawbot-setup/
76 |
77 |
--------------------------------------------------------------------------------
/notes/supplies.md:
--------------------------------------------------------------------------------
1 |
2 | # Autofeed mechanical pencils
3 |
4 | * Penac Non-Stop 0.5
5 | * Faber-Castell Grip Matic $
6 | * Orez Nero $$
7 | * Uni Kuru Toga Dive $$$
8 |
9 | # Techincal pens
10 |
11 | * rOtring isograph (historically used multiple other names: Rapidograph(FJ), Isograph, Variant, Varioscript, micronorm )
12 | - https://unofficialrotring.wordpress.com/2016/04/14/collecting-rotrings-technical-pens/
13 | - https://rotringmuseum.com/
14 | * original rapidograph(1953), variant, variant B, foliograph, micronorm. Compatible nib. Visible air trap path combined with mounting thread.
15 | * isograph(1976-now), nib combined with collar. Supposed to be refillable from bottle, but rotring also sells (small) disposable cartridges. Different from rapidograph(1983) cartridges.
16 | * new rapidograph(1983) uses big "capillary" cartridges, skinny nib, airtrap is part of cartridge instead of nib
17 | * STAEDTLER Mars matic
18 | * Koh-I-Noor® Rapidograph® (previously rapidograph trademark was owned and used by rOtring)
19 | * nib looks similar to Rotring Variant B
20 | * Faber-Castel TG1-S (historically had other TG1 versions like TG1-J TG1-H)
21 |
22 | * Hero 81A (China)
23 | * isomars technoart (India?, their branding and product packaging seems to be heavily inspired by rOtring)
24 | * liquidraw (website, branding and products seem identical to isomars. Alternative brand name? Whitelabelled product?)
25 | * rystor rapidograffffffff "Super Professional Rapidograph" (Poland)
26 | - https://rystor.pl/en/products/technical-pens-and-automatic-pencils/super-professional-rapidograph/
27 |
28 | * Aristo MG1 https://www.aristo.at/ (Austria, Germany)
29 | - currently (2024) owned by GEOTEC
30 | * Standardgraph Stano (Stano Professional, STANDARDGRAPH COLOR, Stano Pen)
31 | - currently (2024) owned by GEOTEC (Austria, Germany)
32 | - https://www.geotec.gmbh/unsere-marken/
33 | - some models are nearly identical to ones sold under Aristo MG1 brand.
34 | * Trident Desegraph (Brazil)
35 | - https://trident.com.br/categoria-produto/canetas-para-desenho/canetas-desegraph-recarregavel/
36 |
37 |
38 |
39 | Historical, closed or doesn't produce technical pens anymore
40 |
41 | * Kern Prontograph (Swiss company, closed factory in 1991) https://www.kern-aarau.ch/kern/willkommen.html
42 | * Centropen centrograph (Czech Republic, still making various writing tools the technical pen not listed on website or latest catalog)
43 | * MECANORMA mg1 (France, looks very similar to Aristo MG1)
44 | * Mutschler (Heidelberg, Germany) [source](https://www.pelikan-collectibles.com/en/Pelikan/Models/Drawing-pen/index.html#heading_toc_j_6)
45 | * reform refograph (Germany)
46 | * reform toz
47 | * Pelikan E-Technik
48 | * ALVIN (US writing tool importer/distributor) has sold under it's brand relabeled technical pens made by various manufacturers
49 | * Mutschler/reform refograph
50 | * Rystor
51 | * isograph like (probably Isomars/technoart or who ever isomars manufacturer is)
52 | * K&E Leroy (USA) better known for their lettering set, but supposedly there were also few K&E Leroy branded rapidograph style technical pens with ink reservoir. (Made by Koh-I-Noor USA)
53 | - http://www.mccoys-kecatalogs.com/
54 | * CLEO SKRIBENT (germany) currently makes only fancy fountain pens
55 | * Polygraph combi, combiscript (germany)
56 | * Herlitz Technoliner (Germany)
57 | * brand got sold to Pelikan () -> Hamelin (2023)
58 | * Unitech (Germany)
59 | * Erograph (Germany)
60 | * Ален Мак, попово (Bulgaria?)
61 | * GG01 Harkov (USSR)
62 |
63 | * "Koh-I-NOOR PROFESIONAL II" looks like relabeled Rystor ???, what is this?
64 |
65 | Other resources:
66 | * https://www.reddit.com/r/Stylographs/
67 | * http://micerveza.es/estilografos%20por%20marca.html (A collection of technical pens from large variety of manufacturers)
68 |
69 |
70 | Useful links
71 | * Comparison diagram with major types of rotring technical pens https://unofficialrotring.wordpress.com/2015/03/19/rotrings-tubular-point-drawing-pens/
72 |
73 | * https://www.rotring.ro/cataloage
74 |
75 |
76 | ## Nib sizes and shapes
77 |
78 | ISO sizes have ratio of √2 ≅ 1.4 . Drawings are supposed to have line thickness proportions of 1:2:4 for thin, normal and thick lines. Ratio of √2 allows easily getting this proprtion by skiping every other size, for example [0.13, 0.25, 0.5] , [0.18, 0.35. 0.7] or [0.25, 0.5. 1.0]
79 |
80 | Newer Statedler marsmatic 750 ISO nibs follow the common color scheme well, but older ones even ISO sizes are all over the place.
81 |
82 | Nibs following the ISO specificiation are often laballed with m̲̅ (m with horizontal lines above and under).
83 |
84 | | mm | ISO | inch | color(ISO) | color rotring | koh-i-noor | FC TG** | Staedtler(1)* | Staedtler(2)* |
85 | | ------ | ------ | ----- | ----------- | ------------- | --------------- | -------------- | -------------- | ------------ |
86 | | | | | | | | | 5x0 MF ochre | |
87 | | | | | | | | | 4x0 UF brown | |
88 | | 0.1mm | | 0.004 | | redish brown | | | 3x0 violet | |
89 | | 0.13mm | ISO(0) | 0.005 | purple | purple | 6x0 teal | | | |
90 | | 0.18mm | ISO(1) | 0.007 | red | red | 4x0 pink | 000 red | | 4x0 red |
91 | | 0.20mm | | 0.008 | | yellow | | | 00 red | |
92 | | 0.25mm | ISO(2) | 0.010 | white | white | 3x0 beige | 00 white | | 3x0 purple |
93 | | 0.30mm | | 0.012 | | olive | 00 yellow | | 0 blue | 00 red |
94 | | 0.35mm | ISO(3) | 0.014 | yellow | yellow | 0 dark gray | 0 yellow | | 0 blue |
95 | | 0.40mm | | 0.016 | | orange | | 1 green | 1 dark green | |
96 | | 0.45mm | | | | | | | | 1 green |
97 | | 0.50mm | ISO(4) | 0.020 | black/brown | brown | 1 brown | 2 brown/orange | 2 yellow | |
98 | | 0.60mm | | 0.024 | | grayish blue | 2 red | 2.25 beige | 2.5 white | |
99 | | 0.70mm | ISO(5) | 0.028 | blue | blue | 2.5 blue | 2.5 blue | | |
100 | | 0.80mm | | 0.031 | | white | 3 green | 3 white | 3 light gray | |
101 | | 1.0mm | ISO(6) | 0.039 | orange | orange | 3.5 light green | 4 orange | 3.5 black | |
102 | | 1.2mm | | 0.047 | | | 4 orange | 5 white | 4 orange | |
103 | | 1.4mm | ISO(7) | 0.055 | blue/green | blue | 6 red | 6 | 5 light green | |
104 | | 2.0mm | ISO(8) | 0.079 | gray | gray | 7 red | 7 gray | 6 dark grey | |
105 |
106 |
107 | *) Color and number varies between generations
108 | **) Color and number varies between generations. Size color accents are only on nib packaging and the pen body not the nib itself. Color of nib is based on type: S yellow, H(tungsten) green, J(jewel) red.
109 |
110 |
111 |
112 | Group refers to the interface between the nib and body maybe the ink reservoir, not the body and cap or body and holder(barell). Barell and cap compatibility can differ.
113 |
114 | In case of long mounting thread, any air grove usually overlaps with mounting thread.
115 |
116 | | manufacturer/model | grp | tip shape | nib unscrew | mounting | air trap | notes |
117 | | ---------------------------------- | --- | --------- | -------------- | ---------------------------- | -------------------------------------------------------------- | -------------------------------------------------------- |
118 | | Rotring, (old)Rapidograph | A | conical | round | long thread | grove across mounting thread | |
119 | | Rotring Variant | A | conical | 2 flats | long thread | grove across mounting thread opposite direction | black with colored ring |
120 | | Rotring Variant B | A | cylinders | 2 flats | long thread | grove across mounting thread, opposite direction | black with colored ring |
121 | | Rotring Foliograph | A | conical | 2 flats | long thread | grove across mounting thread, opposite direction | gray with colored ring |
122 | | Rotring Varioscript | A | conical | 2 flats | long thread | grove across mounting thread | black, flat cone, weird size rang 2-8mm *** |
123 | | Rotring Micronorm | A | conical | 2 flats | long thread | grove across mounting thread, opposite direction | brown with colored ring, flat cone after cylinder |
124 | | Rotring primus**** | A? | conical | radial slots | long thread | grove across mountingh tread, opposite direction | tip conical with radial slots, everything colored |
125 | | Rotring isograph | B | cylinders | N/A | unified nib/body | medium depth spiral in front covered by press fit extra sleeve | 2 metal cylinders * |
126 | | Rotring isograph | B | cylinders | N/A | unified nib/body | medium depth spiral in front covered by press fit extra sleeve | 3mm metal cylinder, 5mm plastic with cone |
127 | | Rotring Rapidograph (1983) | C | cylinders | with cartridge | short thread in front | integrated in ink cartridge instead of nib | whole nib colored |
128 | | Koh-I-Noor | A | conical | 2 flats | long thread | grove across mounting thread | Similar to Variant, sometimes transparent |
129 | | Koh-I-Noor | A | cylinders | 2 flats | long thread | grove across mounting thread | Similar to Variant B , sometimes transparent |
130 | | Leroy K&E | A | cylinders | 2flats | long thread? | ?? | Variant B, Made by Koh-I-Noor USA |
131 | | Staedtler marsmatic | D? | cylinders | hexagon | short thread closer to front | shallow spiral grove with step after each turn | ** |
132 | | Staedtler mars | E? | cylinder | hexagon | long thread | 2x360 groves splitting thread in 3 sections, 2 vertical groves | sometimes first cylinder is made of plastic ** |
133 | | Staedtler mars plot | E? | cylinder | hexagon | long thread | 2x360 groves splitting thread in 3 sections, 2 vertical groves | stubby tip, spring |
134 | | Staedtler mars magno | H | pl cyl | hexagon | short thread closer to front | medium spiral | flat face after hexagon, no body, nib->cartridge->barrel |
135 | | Faber castell TG1 | F | cylinders | short thread | press fit? | shallow contiguous spiral grove | partially transparent |
136 | | Rystor | G | cylinders | 3 notches | long thread/airtrap | medium depth spiral that functions mounting thread | |
137 | | Trident Desegraph | | cylinders | hexagon | long thread | 360 groves + vertical cuts on alternating sides | |
138 | | Reform refograph,Pelikan E-Technik | | cylinders | hexagon | short thread on the back | medium depth compact spiral grove | |
139 | | Standardgrpah stano, MG1 pro | | cylinders | hexagon | long thread | wide spiral grove (2:1 more grove than thread) same direction | |
140 | | Aristo MG1 | | cylinders | N/A | unified nib/body | | looks like Mecanorm MG1 |
141 | | Herlitz Technoliner | | cylinders | hexagon | | | |
142 | | Kern prontograph | | cylinders | hexagon | long thread | wide spiral grove (1:1) | |
143 | | Polygraph combi | | cylinders | hexagon | long thread | steep grove (more like variant) | |
144 | | Liquidraw, Isomars technoart | B? | cylinders | N/A | unified nib | | looks like isograph clone |
145 | | Hero 81A | | conical | octagon | short thread on the back | shallow spiral grove (1:1) | |
146 | | CLEO SKRIBENT | | conical | hexagon | ?? | ?? | |
147 | | GG01 Harkov | F? | cylinders | short thread | press fit? | shallow spiral | |
148 | | Markant Lin | | cylinder | flat? round? | short thread closer to front | shallow wide spiral (2grove:1fin) | |
149 |
150 | *) F versions with tungsten tip have the conical metal parts in golden color. J jeweled tip, P for etching inks.
151 |
152 | **) 2 special versions 757 duranite (tungsten carbide), 759 jewel tip. Some of tungsten ones have golden cylinder (just like rotring), but there are versions that have metalic ring after hexagon instead.
153 |
154 | ***) Size is written like: 10 m/m. Some varioscript adds mention DIN 1451, which is a German font standard. Maybe size refers to which size text you can write using the corresponding nib instead of line width.
155 |
156 | ****) Not to be confused with regular isographs that have primus printed on.
157 |
158 | # Plotter pens
159 |
160 | * Benson Speedypen
161 | * Calcomp
162 | * rotring/koh-i-noor rapidoplot
163 |
164 | rapidoplot Koh-I-Noor naming scheme
165 |
166 | Examples 64NDW-01E, 6810.01M
167 | | 6 | 4NDW | - | 0 | 1 | E |
168 | | --- | ---- | --- | -------- | ----- | ---- |
169 | | | type | | material | color | size |
170 | | | | | 0 paper | | |
171 | | | | | 5 film | | |
172 |
173 |
174 |
175 | | Code | Size |
176 | | ---- | ------ |
177 | | E | 0.25mm |
178 | | F | 0.35mm |
179 | | M | 0.5 mm |
180 | | B | 0.7 mm |
181 |
182 | | Code | Color |
183 | | ---- | --------- |
184 | | 1 | Black |
185 | | 2 | Blue |
186 | | 3 | Green |
187 | | 4 | Red |
188 | | 5 | Yellow |
189 | | 7 | Turqoise |
190 | | 8 | Orange |
191 | | 9 | Brown |
192 | | M | Magenta |
193 | | R | Redviolet |
194 | | V | Violet |
195 |
196 |
197 |
198 | | Code | Type |
199 | | ------- | ------------------------ |
200 | | 6401 | Fiber tip S-style (HP) |
201 | | 6402 | Fiber tip Hi |
202 | | 64NDS | S-style paper |
203 | | 64MDS | S-style film |
204 | | 64NDH | H-style paper |
205 | | 64MDH | H-style film |
206 | | 64NDW | W-style paper |
207 | | 64NDK | K-style paper |
208 | | 6601 | S-style rollerball |
209 | | 6720-3 | E-style direct fit |
210 | | 6810 | A-style universal |
211 | | 6820 | E-style paper direct fit |
212 | | 6920 | E-Style film direct fit |
213 | | | |
214 |
215 |
216 | | rotring name | Koh-I-Noor rapidoplot | | |
217 | | ------------ | --------------------- | ------------------------------------------------------------------------------ | ------------- |
218 | | Type 1 | A-style? | adapters | slim |
219 | | Type 2 | S-style | HP direct fit | has ring |
220 | | Type 3 | H-style | HP with adapter | |
221 | | Type 5 | K-style | HI DMP, BBC/Goerz 28x 29x, Gould 63xx | |
222 | | Type 6 | C-style | Calcomp 800, 900 series direct fit, Calcomp 104x and Hitachi 67x with adapters | |
223 | | Type 7 | Z-Style | Benson, Digigraph, Kongsberg direct fit | slim straight |
224 | | Type 8 | | | |
225 | | Type 9 | W-style | Calcomp 104x direct | has ring |
226 | | Type 20 | E-Style | HP direct fit | has ring |
227 |
228 | F
229 |
230 | A/1P Adaptor list (for A-Style pens)
231 |
232 | |Ploters|Adaptor|
233 | |---|---|
234 | |Houston Instrumental DMP | 7152SLV |
235 | |Hewletter Packard Drafting | 7153SLV |
236 | |Calcomp 102x/104x/20xx | 7154SLV |
237 | |Graphtech |7155SLV |
238 | |Mutoh IP/xP | 7162SLV |
239 | |Mutoh F| 7163SLV |
240 | |Calcomp 9xx/107x| 7164SLV |
241 |
242 | ### Staedtler Marsplot
243 |
244 | | Adaptor | Plotters |
245 | | ---------- | -------------------------------------------------------------------------------------------------------------------- |
246 | | 75PL 00H | Benson, Digigraph, 1208A, Glaser, Kern,Kuhmlmann FR, LR, Xynetics 1000, 1051, 1101, 1201, 2000, 2200, 2600 |
247 | | 75PL 00H10 | Houston instruments CPS 14, 15, 16, 17, 19, 20, 30 DPMP 2, 3, 4, 5, 7, 8, 9, DP 1, 8, 9, 11 |
248 | | 75PL 03H10 | Houston Instrument DMP 2, 3, 4, DMP 5, 6, 7, 8, 9, DMP 29, 40, 41, 42, 50, 51, 52, 55, 56, 61, 62, 51MP, 52 MP, 56MP |
249 | | 75PL 03H11 | BBC-Goerz SE 292, 293 Philips PM 8153 Siemens C1603 Tewidata P293 |
250 | | 75PL 05H | Calcomp 836, 945m 965, 970, 103x 105x 107x Calma 960DDM |
251 | | 75PL 05H1 | Calcomp104X, 104XGT |
252 | | 75PL 07H1 | HP 7090, 7220, 7221, 7225, 7440, 7470, 9872, DMP695A Roland DXY 101, 800, 880, 885, 980, 990 |
253 | | 75PL 07H2 | HP 7550, 7570m 7580, 7585, 7586, 7595, 7596 |
254 | | 75PL 07H3 | Digicon TDD43, Digital LVP16, HP 7475, IBM 7372, United Innovations 8000 |
255 | | 75PL 07H4 | Roland DPX 2000, 2200, 3300 |
256 | | 75PL 08H10 | Gerber 42, 43, 75, 77, 88 Kongensberg 1215, 1216, 1800S, GT5000, 5100, Western Graphtec WX 4671, 4672 |
257 | | 75PL 15H | G.F.I. Digiplot A1 Mutoh Alpha 1000 |
258 | | 75PL 15H1 | Mutoh IP-1000 |
259 | | 75PL 17H | Computervision P 1000, 1100 Nicolet Zeta 8, 822, 824, 824CS, 836, 836CS, 887 |
260 | | 75PL 18H | General Numeric XY, Kuhlmann TRA3. Western Graphtec DA8400, MP1000, 1100, WX 46, WX 48
261 | | 75PL 21H | ADcomp X 300, 300i, Max ADM A3, GA 100, X-Y, Picom Mirwald MP4003, Sekonic SPL 400, 410, Taxan KPL 710 |
262 | | 75PL 22H | Amdek, Amplot II, Graf 672, Hitachi 671, 672, Infograph BIG3, KDC FPL2000, Logitec FPL2000, Neumuller NSA 671, 672, Picom (Mirwald) MP3003 |
263 | | 75PL 22H1 | Hitachi 673, 675, Picom (Mirwald) MP5001 |
264 | | 75PL 23H | Comtec Western Graphtec DA6000, 6100, 6500, FD 5211, FP5201, 5301, 5303, GP9001, 9011, 9011, 9101, MP 2000, 2300, 3100, 3200, 3300, PD9011, 9111, 9311, Mannesmann Tally Pixy 3, Numonics 5412, 5424, 5460, 5600, 5624. 5636, 5860, 6412 |
265 |
266 | | Type | color | Line thickness mm | approx force |
267 | | ---- | ------ | ----------------- | ------------ |
268 | | PL0 | orange | 0.13 - | 0.2N |
269 | | PL1 | purple | 0.18 (0.1) | 0.2N |
270 | | PL2 | red | 0.25 (0.2) | 0.2N |
271 | | PL3 | blue | 0.35 (0.3) | 0.4N |
272 | | PL4 | green | ---- (0.4) | 0.4N |
273 | | PL5 | yellow | 0.50 (0.5) | 0.4N |
274 | | PL6 | white | ---- (0.6) | 0.4N |
275 | | PL8 | gray | 0.80 (0.8) | 0.4N |
276 | | PL10 | | 1.00 (1.0) | 0.4N |
277 |
278 |
279 |
280 | | Art. No. | Size | mark* | Speed | metal color | plastic end | notes |
281 | | ----------- | ------- | ----- | --------------------------- | ----------- | ----------- | ------------------------------------------------------------------------------------------------------------- |
282 | | 750 PLx CF | PL1-10 | CF | 150-300mm/s | silver | yellow | steel point, for plot and tracing paper |
283 | | 750 PLx C3 | PL1-10 | PLOT | 50-200mm/s | silver | black | steel point, for plot and tracing paper |
284 | | 757 PLx CF | PL0-PL8 | T | 500mm/s | gold | yellow | tungsten carbide, for matt drafting film |
285 | | 757 PLx C3 | PL0-10 | | 50-300mm/s | gold | black | tungsten carbide, for matt drafting film |
286 | | 757 PLx CS | PL0-8 | S | 400mm/s | gold | gray | tungsten carbide points with cross groves for increased ink flow, for matt drafting film and glossy OHP film |
287 | | 759 PLx C3 | PL2-10 | | 200mm/s paper, 300mm/s film | gold | red | Jewel-tipped point, for matt drafting film, plotter and tracing paper |
288 | | 757 PLx P | PL0-8 | | >1000 mm/s | | | tungsten carbide, for plotters with pressure controlled ink feed |
289 | | 757 PLx CSP | PL0-8 | | >1000mm/s | | orange | tungsten carbide with cross-groves, for plotters with pressure controlled ink feed |
290 | | 759 PLx P | PL2-10 | | >1000mm/s | | | jewel tipped, for plotters with pressure controlled ink feed |
291 | | 700
292 |
293 | *) additional marking on the sides of hexagon
294 |
295 |
296 | # Pen refilling
297 |
298 | * https://softsolder.com/2015/08/10/hp-7475a-plotter-refilling-the-pens/
299 | * https://softsolder.com/2015/06/06/hp-7475a-plotter-refilling-disposable-liquid-ink-pens/
300 | * https://www.youtube.com/watch?v=h-oj4HrTH14
301 | * https://www.youtube.com/shorts/_c7mn3EfS_g
302 | * https://discord.com/channels/499297341472505858/512391369013198848/1318185339831193621
303 | * https://www.parkablogs.com/content/how-refill-rotring-rapidograph
304 |
305 |
306 | # inks
307 |
308 | * https://www.kalligraphie.com/store/index.php/cat/c54_Inks.html?x84ff7=5i3jf57a9ot5ivpudspmeqbk41
309 | * https://www.octopus-fluids.de/en/write-draw-inks
310 | * https://www.de-atramentis.com/en/document-ink--84/
311 |
312 |
313 | # pens
314 |
315 | * Piano 2121 -> splotchy in corners and start/end of line, inconsistent between pens, 2/2 blocked by air buble
316 | * dong-a fine tech -> clean thin line, endpoint dots, makes air bubbles
317 |
318 |
319 | # communities and resources for other writing tools
320 |
321 | While these often focus on drawing/writing tools which you would rarely use with a pen plotter, they contain some useful historical information and old catalogs from various drawing tool companies.
322 |
323 | * (mechanical pencils) https://forum.knockology.com/
324 | * [Leadholder (web archive link)](https://web.archive.org/web/20110626032321/http://leadholder.com/index-catalog.html)
325 | * https://www.reddit.com/r/pen/
326 | * https://www.reddit.com/r/mechanicalpencils/wiki/index/
327 | * https://www.reddit.com/r/fountainpens/
328 | * https://www.pelikan-collectibles.com/
329 | * https://www.fountainpennetwork.com/forum/
330 | * https://stationery.wiki/Main_Page
331 | * http://dirck.delint.ca/beta/
--------------------------------------------------------------------------------
/notes/vintage_plotter_links.md:
--------------------------------------------------------------------------------
1 |
2 | * http://www.lesporteslogiques.net/wiki/materiel/plotter_roland_dxy-1200
3 | * XY4160 http://www.krupkaj.cz/sblog/article_detail.php?itmid=9000030
4 | * DXY-1150 https://martianwabbit.com/2019/10/25/notes-on-a-roland-dxy-1150.html
5 | * https://hackaday.io/project/12276-roland-dg-dxy-990
6 | * roland DXY-1200 https://www.elektroda.pl/rtvforum/topic1192751.html
7 |
8 | * https://plotterstation.osp.kitchen/catalogue.html
9 | * (a lot of info about most HP plotters) https://www.hpmuseum.net/exhibit.php?class=4&cat=24
10 |
11 | * HP replacement carousel https://www.thingiverse.com/thing:6961560
12 | * https://retrohax.net/atari-1020-plotter-plotting-pens-replacement/
13 |
14 | * https://www.evident-shop.de/en/search?sSearch=stifte
15 | * https://github.com/ithinkido/PlotterROM/tree/main
16 |
17 | # Pen adapters (for vintage plotters)
18 |
19 |
20 | * https://www.thingiverse.com/karliss/collections/43091102/things
21 | * https://github.com/juliendorra/3D-printable-plotter-adapters-for-pens-and-refills (HP)
22 | * https://github.com/aaronbot3000/hp7550-things/tree/master/pen_holders (more HP)
23 | * https://softsolder.com/2015/04/21/hp-7475a-plotter-oem-pen-body-model/ (HP measurements)
24 | * https://github.com/aaronbot3000/hp7550-things/tree/master/pen_holders
25 |
26 | * https://github.com/mmuman/ALPS-plotter-pen-replacement/tree/main (Small capsule thingies)
27 | * https://retrohax.net/atari-1020-plotter-plotting-pens-replacement/
28 |
29 |
30 |
31 | # misc videos
32 |
33 | * https://www.youtube.com/watch?v=YcNpABZoCMI&t=22s hp 7220c
--------------------------------------------------------------------------------
/other_testplots/DMP-60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/DMP-60.png
--------------------------------------------------------------------------------
/other_testplots/atari_1020_color_printer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/atari_1020_color_printer.png
--------------------------------------------------------------------------------
/other_testplots/calcomp_artisan_102x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/calcomp_artisan_102x.png
--------------------------------------------------------------------------------
/other_testplots/dmp_60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/dmp_60.png
--------------------------------------------------------------------------------
/other_testplots/dxy-800_dxy-101.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/dxy-800_dxy-101.png
--------------------------------------------------------------------------------
/other_testplots/hp7475a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/hp7475a.png
--------------------------------------------------------------------------------
/other_testplots/hp7585.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/hp7585.png
--------------------------------------------------------------------------------
/other_testplots/hp_draft_pro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/hp_draft_pro.png
--------------------------------------------------------------------------------
/other_testplots/readme.md:
--------------------------------------------------------------------------------
1 | Collection of demo and test prints from various pen plotters.
--------------------------------------------------------------------------------
/other_testplots/roland-dxy-880.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/roland-dxy-880.png
--------------------------------------------------------------------------------
/other_testplots/roland_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/roland_2.png
--------------------------------------------------------------------------------
/other_testplots/roland_dpx-2000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/roland_dpx-2000.png
--------------------------------------------------------------------------------
/other_testplots/roland_dpx-3300.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/roland_dpx-3300.png
--------------------------------------------------------------------------------
/other_testplots/tektronix_4662.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karliss/plotter_sketches/e81422f6e21684ccf181bb817614e001db15a807/other_testplots/tektronix_4662.png
--------------------------------------------------------------------------------
/test_plot/Readme.md:
--------------------------------------------------------------------------------
1 | # Plotter test file
2 |
3 | For testing plotter and pens.
4 |
5 | When plotting **disable** any **optimizations** which reorder the paths! Certain parts of this file are meant to be plotted in specific order and direction.
6 |
7 |
8 |
9 | ## Checks
10 |
11 | 1) Pen width test, can be used to find what spacing produces solid infill
12 | 2) Spiral
13 | 3) Spiral, larger spacing and path going from outside to the center
14 | 4) Pen width check, same as 1. but vertical
15 | 5) Concentric circles. The middle one is using alternating directions. Pay attention whether circles are concentric, round (not oval) and evenly spaced.
16 | 6) Grid of lines
17 | 7) Text size, size of capital letters in mm
18 | 8) Grid made of rectangles with 1mm and 2mm spacing. Unlike 6 the rectangles cause lines to go in alternating directions.
19 | 9) Grid of rectangles, same as 8. but rotated 45°.
20 | 10) Grid made of squares drawn in randomized order.
21 | 11) Backlash test. 1mm gaps are intentional. To do the test - place a piece of paper (or other flat straight material) along each square edge and check if the line segment from corner piece is aligned with the square edge.
22 |
23 |
24 | 12) empty
25 |
26 | 13) The big square 170mm. Can be used for testing that scale and steps/mm configuration is correct. Can be used for testing axis squareness by comparing diagonal length.
27 | 14) Crosses in the corners of big square. Meant to detect any position shifts during the print, which could be caused by motors skipping steps, paper being insufficiently secured, (in case of roller plotters that move the paper) paper slipping. First set of crosses should be plotted at the start and second set at the end.
28 | 15) Stretched crosses. Possible results (described for horizontal one, but works similarly ):
29 | - all 4 lines cross in the center - good
30 | - diagonal line crossing is shifted to the right or left - movement direction dependent vertical position error
31 |
32 | ## Files
33 |
34 | * test_cal_plot_A4.svg - source file
35 | * \*\_exported.svg - finalized file with all text converted to strokes
36 |
37 | ## Changelog
38 |
39 | * v0.22
40 | - Change the starting point for backlash test 11 so that it doesn't start from corner
41 | - Add 1.25mm font size
42 | - Add feature numbers
43 | - Add feature 15 - stretched crosses
44 | - Add direction arrows
45 | * v0.21 first public version
46 |
--------------------------------------------------------------------------------
/test_plot/shift_compact.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
314 |
--------------------------------------------------------------------------------
/turtletoy/flower.js:
--------------------------------------------------------------------------------
1 | // Forked from "Spiro 1" by kabacis
2 | // https://turtletoy.net/turtle/2a892789a4
3 |
4 | // You can find the Turtle API reference here: https://turtletoy.net/syntax
5 | Canvas.setpenopacity(1);
6 | let stepMul=256;// min=2 max=512 step=1
7 | let offset=-0.7; // min=-1 max=1 step=0.1
8 | let length=57; // min=1 max=200 step=1
9 | let extraRot=-100; // min=-360 max=360 step=5
10 | let a2 = 68; // min=0 max=90 step=1
11 | let scaleX=0.4; // min=0.3 max=1.3 step=0.1
12 | let zfreq=1; // min=0.1 max=10 step=0.01
13 | let z_phase_offset=-0.5; // min=-1 max=1 step=0.05
14 | let h=191; // min=0.0 max=200 step=0.1
15 | let rs=5.65; // min=0.1 max=10 step=0.01
16 | let rVarF = 2.77; // min=0.01 max=10 step=0.01
17 | let rVar = 0.337; // min=0.0 max=4 step=0.001
18 | let lift=0; // min=0, max=1, step=1 (No, Yes)
19 | let verticalOffset = -20; // min=-50, max=50, step=1
20 | let stemL = 81; // min=0, max=100, step=1
21 | let stemB = 3; // min = 0, max=100, step=1
22 |
23 | // Global code will be evaluated once.
24 | const turtle = new Turtle();
25 | turtle.penup();
26 |
27 |
28 | function f(i, down) {
29 | let x = Math.cos(2 * Math.PI * i / stepMul) + offset;
30 | let y = Math.sin(2 * Math.PI * i / stepMul);
31 |
32 |
33 | let rotk = Math.PI * 2 * (Math.floor((i + (down ? 0 : -1)) / stepMul) * rs);
34 | let xt=x;
35 | let yt=y;
36 | x = Math.cos(rotk)*xt-Math.sin(rotk)*yt;
37 | y = Math.sin(rotk)*xt+Math.cos(rotk)*yt;
38 |
39 | let rvarA = Math.PI * 2 * (Math.floor((i + (down ? 0 : -1)) / stepMul) * rVarF);
40 | let r2 = 1 + Math.sin(rvarA) * rVar;
41 |
42 | x *= r2;
43 | y *= r2;
44 |
45 |
46 | let realRot = 2 * Math.PI * extraRot/360;
47 | xt=x;
48 | yt=y;
49 | x = Math.cos(realRot)*xt-Math.sin(realRot)*yt;
50 | y = Math.sin(realRot)*xt+Math.cos(realRot)*yt;
51 |
52 |
53 | let t = (1+Math.cos(zfreq * 2 * Math.PI * i / stepMul))*0.5;
54 | let w = 1;//t;
55 | let z = (1-Math.cos(Math.PI*(t*0.5 + z_phase_offset)))*0.5;
56 |
57 | x *= scaleX * w;
58 | y *= scaleX * w;
59 | z *= h * scaleX;
60 |
61 | x *= 50;
62 | y = 50 * y * Math.cos(Math.PI * a2 / 180) - z * Math.sin(Math.PI * a2 / 180);
63 |
64 | y += verticalOffset;
65 |
66 | turtle.goto(x, y);
67 | }
68 |
69 | turtle.goto(0, verticalOffset);
70 | turtle.pendown();
71 | for (var j=0;j 0 && ((shape & (1< 0) {
157 | s2 |= (1< 0) {
223 | let s1 = q.shift();
224 | let neighbours = next_states(s1);
225 | states[s1] = neighbours;
226 | for (const state of neighbours){
227 | if (!(state in states2)) {
228 | states2[state]=[];
229 | }
230 | states2[state].push(s1);
231 | if (visited[state]) {
232 | continue;
233 | }
234 | visited[state] = true;
235 | q.push(state);
236 | }
237 | order.push(s1);
238 | }
239 | let fillers = -1;
240 | while (order.length < rows*columns) {
241 | order.push(fillers);
242 | states[fillers] = [];
243 | states2[fillers] = [];
244 | fillers -= 1;
245 | }
246 | /*for (let i = order.length - 1; i >= 0; i--) {
247 | let j = Math.floor(Math.random() * (i + 1));
248 | if (j >= i) {
249 | j = 0;
250 | }
251 | let temp = order[i];
252 | order[i] = order[j];
253 | order[j] = temp;
254 | }*/
255 | let dst =0;
256 | for (let i=0; i>>>>>>>> ${x}`);
263 | for (let i=0; i= d1) {
273 | let temp = order[i];
274 | order[i] = order[j];
275 | order[j] = temp;
276 | } else {
277 | // console.log(`tmpswpa ${d1}->${d2} ${i} ${j} ${order[i]} ${order[j]}`);
278 | }
279 | }
280 | }
281 | /*let dst2 =0;
282 | for (let i=0; i= order.length) {
292 | continue;
293 | }
294 | let p = [c * spacing - (columns-1)*spacing*0.5,
295 | r * spacing - (rows-1)*spacing*0.5];
296 | turtle.jump(p);
297 | if (order [index] > 0){
298 | draw_shape(order[index]);
299 |
300 | //console.log(`N: ${states[order[index]]}`);
301 | for (let j=0; j ${order[j]}`)
304 |
305 | if (index == j) {
306 | continue;
307 | }
308 | let c2 = j % columns;
309 | let r2 = Math.floor(j/ columns);
310 | //console.log(`${order[j]} ${c2} ${r2}`);
311 |
312 | let p1 = p;
313 | let p2 = [c2 * spacing - (columns-1)*spacing*0.5,
314 | r2 * spacing - (rows-1)*spacing*0.5];
315 |
316 | let dx = p2[0] -p1[0];
317 | let dy = p2[1] -p1[1];
318 | if (Math.abs(r-r2) ==1 && Math.abs(c-c2) == 1) {
319 | if (p1[1] < p2[1]) {
320 | p1[1] += 2 * scale;
321 | } else {
322 | p2[1] += 2 * scale;
323 | }
324 | }
325 |
326 | turtle.jump(p);
327 | for (let t=0; t<1; t += (1.0/128.0)) {
328 |
329 | let px =slerp(p1[0], p2[0], t);
330 | let py =slerp(p1[1], p2[1], t);
331 | let shift = bend*scale * (1 - 4 * ((t-0.5)*(t-0.5))) * Math.min(bendLimit, (((Math.abs(dx)+Math.abs(dy)) / spacing)-1));
332 | if (Math.abs(dx) < Math.abs(dy)) {
333 | px += shift;
334 | } else {
335 | py -= shift;
336 | }
337 | if (xydist(p, [px, py]) < scale*lineDist ||
338 | xydist(p2, [px, py]) < scale*lineDist ) {
339 | turtle.penup();
340 | } else {
341 | turtle.pendown();
342 | }
343 | turtle.goto(px, py);
344 | }
345 | turtle.goto(p2);
346 | }
347 | }
348 |
349 | }
350 | index++;
351 | }
352 | }
353 | return false;
354 | }
355 |
356 | /*function walk(i) {
357 | if (q.length <= 0) {
358 | return false;
359 | }
360 | if (rc[1] >= columns) {
361 | rc[1] = 0;
362 | rc[0] += 1;
363 | }
364 | if (rc[0] >= rows) {
365 | return false;
366 | }
367 | let s1 = q.shift();
368 | turtle.jump([rc[1] * spacing - (columns-1)*spacing*0.5,
369 | rc[0] * spacing - (rows-1)*spacing*0.5]);
370 | draw_shape(s1);
371 | let neighbours = next_states(s1);
372 | for (const state of neighbours){
373 | if (state in visited) {
374 | continue;
375 | }
376 | visited[state] = true;
377 | q.push(state);
378 | }
379 | rc[1] += 1;
380 | //turtle.jump(0, 0);
381 | //draw_shape(0x77);
382 | return true;
383 | }*/
--------------------------------------------------------------------------------
/turtletoy/hex_grid.js:
--------------------------------------------------------------------------------
1 | // You can find the Turtle API reference here: https://turtletoy.net/syntax
2 | // https://turtletoy.net/turtle/5c7899fc39
3 |
4 | Canvas.setpenopacity(1);
5 |
6 | // Global code will be evaluated once.
7 | const turtle = new Turtle();
8 | turtle.penup();
9 |
10 |
11 | const SIZE = 200;
12 | const SIZE_HALF = 100;
13 |
14 | class V2 {
15 | constructor(x, y) {
16 | this.x = x;
17 | this.y = y;
18 | }
19 | add(b) { return new V2(this.x + b.x, this.y + b.y); }
20 | sub(b) { return new V2(this.x - b.x, this.y - b.y); }
21 | mul(b) { return new V2(this.x * b, this.y * b); }
22 | flipx() { return new V2(-this.x, this.y); }
23 | flipy() { return new V2(this.x, -this.y); }
24 | }
25 | function deg2rad(a) { return a / 180 * Math.PI; }
26 | const v1 = new V2(Math.sin(deg2rad(60)), Math.cos(deg2rad(60)));
27 |
28 | let dimension_mode = 1; // min=1 max=2 step=1 (rows_columns, width_height)
29 | let rows = 11; // min=1 max=100 step=2
30 | let cols = 10; // min=1 max=100 step=1
31 | let width = 210; // min = 10 max=500 step=1
32 | let height = 297; // min = 10 max=500 step=1
33 | let edge_length = 10; // min=1 max=100 step=1
34 | let l = edge_length;
35 |
36 | const v1s = v1.mul(l);
37 |
38 | if (dimension_mode == 2) {
39 | rows = Math.floor((height - v1s.y) / (l + v1s.y));
40 | if (rows % 2 == 0) {
41 | rows -= 1;
42 | }
43 | cols = Math.floor(width / (2 * v1s.x));
44 | }
45 |
46 |
47 | const vert = new V2(0, -l);
48 |
49 |
50 | let p = (new V2(Math.floor(0) * v1s.x * 2, 0)).add(new V2(-SIZE_HALF + v1s.x, SIZE_HALF - 0 - v1s.y));
51 | turtle.goto(p.x, p.y);
52 | turtle.pendown();
53 | // The walk function will be called until it returns false.
54 | function walk(i) {
55 | if (i < cols) {
56 | for (let d=0; d<2; d++) {
57 | let v = v1s.mul(-1);
58 | let down = vert;
59 | if (d % 2) {
60 | v = v.mul(-1);
61 | down = down.mul(-1);
62 | }
63 | for (let j=0; j 0) {
95 | while (this.tile.connections[d2] != g0) {
96 | d2 = (d2+1)%6;
97 | }
98 | } else {
99 | d2 = d;
100 | }
101 | // console.log(d2);
102 | let k = (d2 - d + 6) % 6;
103 | //console.log(loops[k]);
104 | loops[k].forEach((v) => {
105 | p.push(v.rotDeg(60 * i));
106 | });
107 | turtle.jump(pv2.add(p[0]).outp());
108 | for (let i=1; i 0;
132 | }
133 |
134 | fullSymetry() {
135 | return this.symetry[0]+this.symetry[1]+this.symetry[2] == 3;
136 | }
137 | angledSymetry() {
138 | return this.symetry[3] > 0;
139 | }
140 | place(dir) {
141 | return new PlacedTile(this, dir);
142 | }
143 |
144 |
145 | }
146 |
147 | const tiles = [
148 | new Tile([1,1,1,1,1,1], [1, 1, 1, 1]),
149 | new Tile([0,0,0,0,0,0], [1, 1, 1, 1]),
150 | new Tile([1,1,2,2,3,3], [0, 0, 0, 1]), // othersymb
151 | new Tile([1,2,2,1,3,3], [1, 0, 0, 0]) ,
152 | new Tile([1,0,0,1,0,0], [1, 0, 0, 0]) ,
153 | new Tile([1,1,0,1,0,1], [1, 0, 0, 0]) ,
154 | new Tile([0,1,1,0,2,2], [1, 0, 0, 0]),
155 | new Tile([0,1,1,0,1,1], [1, 0, 0, 0]),
156 | new Tile([1,2,2,1,0,1], [0, 0, 0, 0]),
157 | new Tile([1,1,1,0,0,1], [0, 0, 0, 1]),
158 | new Tile([1,1,2,3,3,2], [0, 0, 0, 1]),
159 | ];
160 |
161 |
162 |
163 |
164 |
165 | //turtle.penup();
166 | //turtle.goto(0, 0);
167 |
168 | let data=[];
169 | turtle.pendown();
170 | for (let y=0; y {
180 | let good = true;
181 | if ((x == 0 && y == 0)) {
182 | good = t.fullSymetry();
183 | } else if (x == y) {
184 | good = t.angledSymetry();
185 | } else if (y == 0) {
186 | good = t.isSymetric(0);
187 | }
188 | if (good) {
189 | candidates.push(t);
190 | }
191 | });
192 | if (x+y > W) {
193 | candidates = [tiles[1]];
194 | }
195 | let rot = 0;
196 | let tile = candidates[randInt(candidates.length)];
197 | if (y == 0 && x > 0) {
198 | rot = randInt(2)*3;
199 | } else if (x == y) {
200 | rot = 1+randInt(2)*3;
201 | }else {
202 | rot = randInt(6);
203 | }
204 | let pt = tile.place(rot);
205 | line.push(pt);
206 | }
207 | data.push(line);
208 | }
209 | for (let x=0; x 0 && x==0) {
214 | continue;
215 | }
216 | for (let r=0; r,
39 |
40 |
41 | #[skip]
42 | #[serde(skip)]
43 | dstate: DynamicState,
44 | }
45 |
46 | #[derive(Default)]
47 | struct DynamicState {
48 | path_loaded: String,
49 | image: ImageBuffer, Vec>,
50 | }
51 |
52 | impl Default for DitherSketch {
53 | fn default() -> Self {
54 | Self {
55 | line_size: 1.0,
56 | grid_mul: 1.0,
57 | path: String::default(),
58 | have_image: false,
59 | scale_mul: 1.0,
60 | w: 0,
61 | h: 0,
62 | mode: DitherMode::default(),
63 | pattern: Vec::default(),
64 | dstate: DynamicState::default(),
65 | }
66 | }
67 | }
68 |
69 | impl DitherSketch {
70 | fn load_image(&mut self) -> Result<(), ()> {
71 | let mut img = ImageReader::open(&self.path)
72 | .map_err(|e| ())?
73 | .decode()
74 | .map_err(|e| ())?
75 | .to_rgb8();
76 |
77 | let w2 = (img.width()as f64 * self.scale_mul) as u32;
78 | let h2 = (img.height()as f64 * self.scale_mul) as u32;
79 | self.w = w2;
80 | self.h = h2;
81 |
82 | let img = image::imageops::resize(
83 | &img,
84 | w2,
85 | h2,
86 | image::imageops::FilterType::CatmullRom,
87 | );
88 |
89 | self.dstate.image = img;
90 | self.dstate.path_loaded = self.path.clone();
91 | return Ok(());
92 | }
93 | }
94 |
95 | fn pixel_magnitude2(p: Rgb) -> i32 {
96 | let c = p.channels();
97 | return c[0] as i32 * c[0] as i32 + c[1] as i32 * c[1] as i32 + c[2] as i32 * c[2] as i32;
98 | }
99 |
100 | type IPos2 = Vector2;
101 |
102 | fn pixel_to_vec32f(p: Rgb) -> Vector3 {
103 | return Vector3::new(p.0[0] as f32, p.0[1] as f32, p.0[2] as f32);
104 | }
105 |
106 |
107 | struct HeapPos {
108 | cost: f32,
109 | pos: IPos2,
110 | prev: IPos2,
111 | }
112 |
113 |
114 | impl PartialEq for HeapPos {
115 | fn eq(&self, other: &Self) -> bool {
116 | self.cost == other.cost
117 | }
118 | }
119 | impl PartialOrd for HeapPos {
120 | fn partial_cmp(&self, other: &Self) -> Option {
121 | return Some(self.cmp(other));
122 | }
123 | }
124 | impl Ord for HeapPos {
125 | fn cmp(&self, other: &Self) -> std::cmp::Ordering {
126 | return other.cost.total_cmp(&self.cost);
127 | }
128 | }
129 | impl Eq for HeapPos {
130 |
131 | }
132 |
133 | pub fn grid_cell(grid: f64, pos: IPos2) -> Vec2 {
134 | return Vec2::new(pos.x as f64 * grid, pos.y as f64 * grid);
135 | }
136 |
137 | fn dither_a(state: &mut DitherSketch, sketch: &mut Sketch)
138 | {
139 | let image = &state.dstate.image;
140 | let gs = state.line_size * state.grid_mul;
141 |
142 | let grid = Grid::from_cell_size([gs, gs])
143 | .columns(state.w as usize)
144 | .rows(state.h as usize);
145 |
146 |
147 |
148 |
149 | let mina = [
150 | [0, 8, 2,10],
151 | [12, 4,14, 6],
152 | [ 3,11, 1, 9],
153 |
154 | [15, 7, 13, 5]
155 | ];
156 |
157 |
158 |
159 | /*grid.build(sketch, |sketch, cell| {
160 | let p1 = cell.position;
161 | let p2 = p1 + Point::new(cell.size[0], 0);
162 |
163 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
164 | if pixel_magnitude2(*c1).isqrt() > (443/2) {
165 | sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
166 | }
167 | });*/
168 |
169 | grid.build(sketch, |sketch, cell| {
170 | let p1 = cell.position;
171 | let p2 = p1 + Point::new(cell.size[0]*0.1, 0);
172 |
173 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
174 | let mg = pixel_magnitude2(*c1).isqrt();
175 |
176 | let a = mina[cell.row % mina.len()][cell.column % mina[0].len()];
177 |
178 |
179 | //if mg < ((443) * (a+1)) / 17
180 | if 443-mg > ((443) * (a+1)) / 17
181 | {
182 | sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
183 | }
184 | });
185 | }
186 |
187 |
188 | fn dither_b(state: &mut DitherSketch, sketch: &mut Sketch)
189 | {
190 | let image = &state.dstate.image;
191 | let gs = state.line_size * state.grid_mul;
192 |
193 | let grid = Grid::from_cell_size([gs, gs])
194 | .columns(state.w as usize)
195 | .rows(state.h as usize);
196 |
197 |
198 | let dir = [
199 | [ 2, 2, 2, 1, 2, 2, 2, 1],
200 | [ 2, 1, 2, 1, 2, 1, 2, 1],
201 | [ 2, 2, 2, 1, 2, 2, 2, 1],
202 | [ 2, 1, 2, 1, 2, 1, 2, 1],
203 |
204 | [ 2, 2, 2, 1, 2, 2, 2, 1],
205 | [ 2, 1, 2, 1, 2, 1, 2, 1],
206 | [ 2, 2, 2, 1, 2, 2, 2, 1],
207 | [ 2, 1, 2, 1, 2, 1, 2, 1],
208 | ];
209 |
210 | /*let mina = [
211 | [ 6, 5, 4, 0, 4, 5, 6, 0],
212 | [13,10,12, 1, 12,11,13, 1],
213 | [ 7, 8, 9, 2, 9, 8, 7, 2],
214 | [14,11,15, 3, 15,10,14, 3],
215 |
216 | [ 4, 5, 6, 0, 6, 5, 4, 0],
217 | [12,11,13, 1, 13,10,12, 1],
218 | [ 9, 8, 7, 2, 7, 8, 9, 2],
219 | [15,10,14, 3, 14,11,15, 3],
220 | ];*/
221 |
222 | let mina = [
223 | [ 6, 5, 4, 2, 4, 5, 6, 0],
224 | [13,10,12, 1, 12,11,13, 1],
225 | [ 7, 8, 9, 0, 9, 8, 7, 2],
226 | [14,11,15, 3, 15,10,14, 3],
227 |
228 | [ 4, 5, 6, 2, 6, 5, 4, 0],
229 | [12,11,13, 1, 13,10,12, 1],
230 | [ 9, 8, 7, 0, 7, 8, 9, 2],
231 | [15,10,14, 3, 14,11,15, 3],
232 | ];
233 |
234 |
235 | let flip = [
236 | [99,99,99,99, 99,99,99,99],
237 | [99,99,99,99, 99,99,99,99],
238 | [99,99,99,99, 99,99,99,99],
239 | [99,99,99,99, 99,99,99,99],
240 |
241 | [99,99,99,99, 99,99,99,99],
242 | [99,99,99,99, 99,99,99,99],
243 | [99,99,99,99, 99,99,99,99],
244 | [99,99,99,99, 99,99,99,99],
245 | ];
246 |
247 |
248 |
249 | /*grid.build(sketch, |sketch, cell| {
250 | let p1 = cell.position;
251 | let p2 = p1 + Point::new(cell.size[0], 0);
252 |
253 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
254 | if pixel_magnitude2(*c1).isqrt() > (443/2) {
255 | sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
256 | }
257 | });*/
258 |
259 | let mut flags = ImageBuffer::from_fn(image.width(), image.height(), |x, y| {
260 | image::Luma([0u8])
261 | });
262 |
263 | grid.build(sketch, |sketch, cell| {
264 | let p1 = cell.position;
265 | let p2 = p1 + Point::new(cell.size[0]*0.1, 0);
266 |
267 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
268 | let mg = pixel_magnitude2(*c1).isqrt();
269 |
270 | let W = mina.len();
271 | let a: i32 = mina[cell.row % W][cell.column % W];
272 | let d: i32 = dir[cell.row % W][cell.column % W];
273 |
274 |
275 |
276 | if 443-mg > ((443) * (a+1)) / 17 {
277 | *flags.get_pixel_mut(cell.column as u32, cell.row as u32) = Luma([d as u8; 1]);
278 | //sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
279 | }
280 | });
281 | for y in 0..(state.h as u32) {
282 | let mut x = 0u32;
283 | while x < state.w {
284 | if flags.get_pixel(x, y )[0] != 2 {
285 | x += 1;
286 | continue;
287 | }
288 | let first = x;
289 | let mut last_need = x;
290 | while x < (state.w as u32) && flags.get_pixel(x, y)[0] > 0 {
291 | if flags.get_pixel(x, y)[0] == 2 {
292 | last_need = x;
293 | }
294 | x += 1;
295 | }
296 | let v1 = first as f64;
297 | let mut v2 = last_need as f64;
298 | if first == last_need {
299 | v2 += 0.01;
300 | }
301 | sketch.line(v1 * gs, y as f64 * gs, v2 * gs, y as f64 * gs);
302 | }
303 | }
304 | for x in 0..(state.w as u32) {
305 | let mut y = 0u32;
306 | while y < state.h {
307 | if flags.get_pixel(x, y )[0] != 1 {
308 | y += 1;
309 | continue;
310 | }
311 | let first = y;
312 | let mut last_need = first;
313 | while y < (state.h as u32) && flags.get_pixel(x, y)[0] > 0 {
314 | if flags.get_pixel(x, y)[0] == 1 {
315 | last_need = y;
316 | }
317 | y += 1;
318 | }
319 | let v1 = first as f64;
320 | let mut v2 = last_need as f64;
321 | if first == last_need {
322 | v2 += 0.01;
323 | }
324 | sketch.line(x as f64 * gs, v1 * gs, x as f64 * gs, v2 * gs);
325 | }
326 | }
327 | }
328 |
329 |
330 | fn join_xpattern(state: &mut DitherSketch, sketch: &mut Sketch, flags: &mut ImageBuffer, Vec>)
331 | {
332 | let gs = state.line_size * state.grid_mul;
333 | for y in 0..(state.h) {
334 | for x in 0..state.w {
335 | if flags.get_pixel(x, y)[0] == 0 {
336 | continue;
337 | }
338 | let mut f2:u8 = 1;
339 | if let Some(v) = flags.get_pixel_checked(x.wrapping_sub(1), y.wrapping_sub(1)) {
340 | if v[0] > 0 {
341 | f2 |= 2;
342 | }
343 | }
344 | if let Some(v) = flags.get_pixel_checked(x+1, y+1) {
345 | if v[0] > 0 {
346 | f2 |= 2;
347 | }
348 | }
349 | if let Some(v) = flags.get_pixel_checked(x.wrapping_sub(1), y+1) {
350 | if v[0] > 0 {
351 | f2 |= 4;
352 | }
353 | }
354 | if let Some(v) = flags.get_pixel_checked(x+1, y.wrapping_sub(1)) {
355 | if v[0] > 0 {
356 | f2 |= 4;
357 | }
358 | }
359 | *flags.get_pixel_mut(x, y) = Luma([f2; 1]);
360 | }
361 | }
362 | for x0 in (-(state.h as i32))+1..(state.w as i32) {
363 | let (y0, x0) = if x0 < 0 {
364 | ((-x0) as u32, 0)
365 | } else {
366 | (0, (x0 as u32))
367 | };
368 | let mut x = x0;
369 | let mut y=y0;
370 | while x < state.w && y < state.h {
371 | let f0 = flags.get_pixel(x, y)[0];
372 | if f0 == 0 {
373 | x += 1;
374 | y += 1;
375 | } else {
376 | let p0 = (x, y);
377 | while x < state.w && y < state.h && flags.get_pixel(x, y)[0] > 0 {
378 | x += 1;
379 | y += 1;
380 | }
381 | if (x - p0.0) > 1 || (f0 & 4 == 0) {
382 | sketch.line(gs * p0.0 as f64, gs * p0.1 as f64, gs * (x as f64 - 0.99), gs * (y as f64 - 0.99));
383 | }
384 | }
385 | }
386 | }
387 | for x0 in 0..state.w + state.h - 1 {
388 | let (y0, x0) = if x0 >= state.w {
389 | (x0 - state.w + 1, state.w - 1)
390 | } else {
391 | (0, (x0 as u32))
392 | };
393 | let x0 = x0 as u32;
394 | let mut x = x0 as i32;
395 | let mut y= y0;
396 | while x >= 0 && y < state.h {
397 | let f0 = flags.get_pixel(x as u32, y)[0];
398 | if f0 == 0 {
399 | x -= 1;
400 | y += 1;
401 | } else {
402 | let p0 = (x, y);
403 | while x >= 0 && y < state.h && flags.get_pixel(x as u32, y)[0] > 0 {
404 | x -= 1;
405 | y += 1;
406 | }
407 | if y - p0.1 > 1 {
408 | sketch.line(gs * p0.0 as f64, gs * p0.1 as f64, gs * (x as f64 + 0.99), gs * (y as f64 - 0.99));
409 | }
410 | }
411 | }
412 | }
413 | }
414 |
415 |
416 | fn dither_ax(state: &mut DitherSketch, sketch: &mut Sketch)
417 | {
418 | let image = &state.dstate.image;
419 | let gs = state.line_size * state.grid_mul;
420 |
421 | let grid = Grid::from_cell_size([gs, gs])
422 | .columns(state.w as usize)
423 | .rows(state.h as usize);
424 |
425 |
426 | let mina = [
427 | [0, 8, 2,10],
428 | [12, 4,14, 6],
429 | [ 3,11, 1, 9],
430 | [15, 7, 13, 5]
431 | ];
432 |
433 |
434 | let mut flags = ImageBuffer::from_fn(image.width(), image.height(), |_x, _y| {
435 | image::Luma([0u8])
436 | });
437 |
438 |
439 |
440 | grid.build(sketch, |sketch, cell| {
441 | let p1 = cell.position;
442 | let p2 = p1 + Point::new(cell.size[0]*0.1, 0);
443 |
444 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
445 | let mg = pixel_magnitude2(*c1).isqrt();
446 |
447 | let W = mina.len();
448 | let a: i32 = mina[cell.row % W][cell.column % W];
449 |
450 |
451 | if 443-mg > ((443) * (a+1)) / 17 {
452 | *flags.get_pixel_mut(cell.column as u32, cell.row as u32) = Luma([1 as u8; 1]);
453 | //sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
454 | }
455 | });
456 | join_xpattern(state, sketch, &mut flags);
457 | }
458 |
459 | fn dither_randx(state: &mut DitherSketch, sketch: &mut Sketch, ctx: &mut Context)
460 | {
461 | let image = &state.dstate.image;
462 | let gs = state.line_size * state.grid_mul;
463 |
464 | let grid = Grid::from_cell_size([gs, gs])
465 | .columns(state.w as usize)
466 | .rows(state.h as usize);
467 |
468 |
469 | let mina = [
470 | [0, 8, 2,10],
471 | [12, 4,14, 6],
472 | [ 3,11, 1, 9],
473 | [15, 7, 13, 5]
474 | ];
475 |
476 |
477 | let mut flags = ImageBuffer::from_fn(image.width(), image.height(), |_x, _y| {
478 | image::Luma([0u8])
479 | });
480 |
481 |
482 |
483 | grid.build(sketch, |sketch, cell| {
484 | let p1 = cell.position;
485 | let p2 = p1 + Point::new(cell.size[0]*0.1, 0);
486 |
487 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
488 | let mg = pixel_magnitude2(*c1).isqrt();
489 |
490 | let W = mina.len();
491 | let a: i32 = mina[cell.row % W][cell.column % W];
492 |
493 |
494 | if 443-mg > ctx.rng_range(0..443) {
495 | *flags.get_pixel_mut(cell.column as u32, cell.row as u32) = Luma([1 as u8; 1]);
496 | //sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
497 | }
498 | });
499 | join_xpattern(state, sketch, &mut flags);
500 | }
501 |
502 |
503 | fn dither_xpat(state: &mut DitherSketch, sketch: &mut Sketch, mina: &[[i32; 4]; 4])
504 | {
505 | let image = &state.dstate.image;
506 | let gs = state.line_size * state.grid_mul;
507 |
508 | let grid = Grid::from_cell_size([gs, gs])
509 | .columns(state.w as usize)
510 | .rows(state.h as usize);
511 |
512 |
513 | let mut flags = ImageBuffer::from_fn(image.width(), image.height(), |_x, _y| {
514 | image::Luma([0u8])
515 | });
516 |
517 |
518 | grid.build(sketch, |sketch, cell| {
519 | let p1 = cell.position;
520 | let p2 = p1 + Point::new(cell.size[0]*0.1, 0);
521 |
522 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
523 | let mg = pixel_magnitude2(*c1).isqrt();
524 |
525 | let W = mina.len();
526 | let a: i32 = mina[cell.row % W][cell.column % W];
527 |
528 |
529 | if 443-mg > ((443) * (a+1)) / 17 {
530 | *flags.get_pixel_mut(cell.column as u32, cell.row as u32) = Luma([1 as u8; 1]);
531 | //sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
532 | }
533 | });
534 | join_xpattern(state, sketch, &mut flags);
535 | }
536 |
537 |
538 | fn dither_xopt1(state: &mut DitherSketch, sketch: &mut Sketch)
539 | {
540 | let mina = [
541 | [12, 7, 8, 0],
542 | [ 5,13, 1,10],
543 | [11, 2,14, 6],
544 | [ 3, 9, 4,14]
545 | ];
546 | return dither_xpat(state, sketch, &mina);
547 | }
548 |
549 | fn dither_xopt2(state: &mut DitherSketch, sketch: &mut Sketch)
550 | {
551 | let mina = [
552 | [15, 5,11, 0],
553 | [ 6,12, 1,10],
554 | [13, 2, 9, 4],
555 | [ 7 ,8, 3,14]
556 | ];
557 | return dither_xpat(state, sketch, &mina);
558 | }
559 |
560 |
561 | impl App for DitherSketch {
562 | fn update(&mut self, sketch: &mut Sketch, _ctx: &mut Context) -> anyhow::Result<()> {
563 | if self.path != self.dstate.path_loaded {
564 | match self.load_image() {
565 | Err(_) => {
566 | std::eprintln!("Failed to load image");
567 | self.have_image = false;
568 | }
569 | Ok(_) => {
570 | self.have_image = true;
571 | }
572 | }
573 | self.dstate.path_loaded = self.path.clone();
574 | }
575 | if self.dstate.image.is_empty() {
576 | eprintln!("No image");
577 | return Ok(());
578 | }
579 | sketch.scale(Unit::Mm);
580 |
581 | sketch.stroke_width( vsvg::Unit::Mm.convert_to(&vsvg::Unit::Px, self.line_size) );
582 |
583 |
584 | match self.mode {
585 | DitherMode::Ordered8Dot => {
586 | dither_a(self, sketch);
587 | }
588 | DitherMode::HV1 => {
589 | dither_b(self, sketch);
590 | }
591 | DitherMode::BayerXJoin => {
592 | dither_ax(self, sketch);
593 | }
594 | DitherMode::XJoinOpt1 => {
595 | dither_xopt1(self, sketch);
596 | }
597 | DitherMode::XJoinOpt2 => {
598 | dither_xopt2(self, sketch);
599 | }
600 | DitherMode::XJoinOpt3 => {
601 | let mut pat = [[0; 4]; 4];
602 | for (i, v) in self.pattern.iter().enumerate() {
603 | if i < 16 {
604 | pat[i/4][i % 4] = *v;
605 | }
606 | }
607 | dither_xpat(self, sketch, &pat);
608 | }
609 | DitherMode::Random => {
610 | dither_randx(self, sketch, _ctx);
611 | }
612 | }
613 | Ok(())
614 | }
615 | }
616 |
617 | fn main() -> whiskers::prelude::Result {
618 | DitherSketch::runner()
619 | .with_page_size_options(PageSize::A5H)
620 | .with_layout_options(LayoutOptions::Center)
621 | .run()
622 | }
623 |
--------------------------------------------------------------------------------
/vsvg/simple/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "plotter_sketches_vsg_simple"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | whiskers = { git = "https://github.com/abey79/vsvg.git" }
10 | vsvg = { git = "https://github.com/abey79/vsvg.git" }
11 | image = "0.25"
12 | nalgebra = "0.33"
--------------------------------------------------------------------------------
/vsvg/simple/examples/christmas_tree.rs:
--------------------------------------------------------------------------------
1 | //! This example demonstrates the use of the [`HexGrid`] helper.
2 |
3 | use egui::lerp;
4 | use vsvg::UNITS;
5 | use whiskers::prelude::*;
6 |
7 | #[sketch_app]
8 | struct HexGridSketch {
9 | #[param(min = 0.01, max = 100.0)]
10 | line_size: f64,
11 | is_pointy_orientation: bool,
12 | #[param(slider, min = 2, max = 100)]
13 | columns: usize,
14 | #[param(slider, min = 2, max = 100)]
15 | rows: usize,
16 | #[param(slider, min = 0.0, max = 200.0)]
17 | spacing: f64,
18 | #[param(min = 0.0, max = 100.0)]
19 | cell_size: f64,
20 | #[param(slider, min = 0.0, max = 1.0)]
21 | tree_h: f64,
22 | #[param(slider, min = 2, max = 20)]
23 | levels: i32,
24 | #[param(slider, min = 0.0, max = 1.0)]
25 | branch_h: f64,
26 | #[param(slider, min = 0.0, max = 90.0)]
27 | angle: f64,
28 | #[param(slider, min = 0.0, max = 1.0)]
29 | max_w: f64,
30 | #[param(slider, min = 0.0, max = 1.0)]
31 | min_w: f64,
32 | random: bool,
33 |
34 | #[param(slider, min = 0.0, max = 360.0)]
35 | angle2: f64,
36 | #[param(slider, min = 0.0, max = 1.0)]
37 | rot_center: f64
38 | }
39 |
40 | impl Default for HexGridSketch {
41 | fn default() -> Self {
42 | Self {
43 | line_size: 1.0,
44 | columns: 5,
45 | rows: 5,
46 | spacing: 0.0,
47 | is_pointy_orientation: false,
48 | cell_size: 40.0,
49 | tree_h: 0.7,
50 | levels: 2,
51 | angle: 45.0,
52 | branch_h: 0.6,
53 | max_w: 0.5,
54 | min_w: 0.05,
55 | random: false,
56 | angle2: 0.0,
57 | rot_center: 0.5,
58 | }
59 | }
60 | }
61 |
62 | impl App for HexGridSketch {
63 | fn update(&mut self, sketch: &mut Sketch, _ctx: &mut Context) -> anyhow::Result<()> {
64 | sketch.stroke_width(self.line_size);
65 |
66 | let grid = if self.is_pointy_orientation {
67 | HexGrid::with_pointy_orientation()
68 | } else {
69 | HexGrid::with_flat_orientation()
70 | };
71 |
72 | sketch.scale(Unit::Mm);
73 |
74 | grid.cell_size(self.cell_size)
75 | .columns(self.columns)
76 | .rows(self.rows)
77 | .spacing(self.spacing)
78 | .build(sketch, |sketch, cell| {
79 | let b = Point::new(0.0, 0.0); //cell.center;
80 | let top = b + Point::new(0, -self.cell_size * self.tree_h);
81 | let mut points = vec![b, top];
82 | for i in 0..self.levels {
83 | let frac = i as f64 / self.levels as f64;
84 | let start = Point::new(0, top.y() - (top.y() * self.branch_h) * frac);
85 | points.push(start);
86 | let w = top.y().abs() * lerp(self.min_w..=self.max_w, frac);
87 | let br_h = w / self.angle.to_radians().tan();
88 | points.push(start + Point::new(-w, br_h));
89 | points.push(start);
90 | points.push(start + Point::new(w, br_h));
91 | points.push(start);
92 | }
93 | sketch.push_matrix();
94 |
95 |
96 | sketch.translate(cell.center.x(), cell.center.y());
97 | sketch.rotate_around(
98 | Angle::from_deg(self.angle2),
99 | 0.0,
100 | top.y() * self.rot_center,
101 | );
102 | if self.random {
103 | sketch.rotate_around(
104 | Angle::from_deg(60f64 * _ctx.rng_range(0..6) as f64),
105 | 0.0,
106 | top.y() * self.rot_center,
107 | );
108 | }
109 |
110 | sketch.polyline(points, true).pop_matrix();
111 | //sketch.add_path(cell);
112 | });
113 |
114 | Ok(())
115 | }
116 | }
117 |
118 | fn main() -> Result {
119 | HexGridSketch::runner()
120 | .with_page_size_options(PageSize::A5H)
121 | .with_layout_options(LayoutOptions::Center)
122 | .run()
123 | }
124 |
--------------------------------------------------------------------------------
/vsvg/simple/examples/circles.rs:
--------------------------------------------------------------------------------
1 |
2 | use image::{GenericImageView, ImageBuffer, ImageReader, Luma, Pixel, Rgb};
3 | use kurbo::Vec2;
4 | use nalgebra::{vector, Vector2, Vector3};
5 | use serde;
6 | use std::result::Result;
7 | use vsvg::UNITS;
8 | use whiskers::prelude::*;
9 |
10 |
11 | #[sketch_app]
12 | struct CircleSketch {
13 | #[param(slider, min = 0.01, max = 5.0)]
14 | line_size: f64,
15 | grid_mul: f64,
16 | path: String,
17 | have_image:bool,
18 | scale_mul: f64,
19 | w: u32,
20 | h: u32,
21 |
22 | circles: usize,
23 | black_max: i32,
24 | rings: i32,
25 | #[param(slider, min = 0.1, max = 20.0)]
26 | spacing: f64,
27 |
28 | subdiv: i32,
29 |
30 | priority: bool,
31 | invert: bool,
32 |
33 |
34 |
35 | #[skip]
36 | #[serde(skip)]
37 | dstate: DynamicState,
38 | }
39 |
40 | #[derive(Default)]
41 | struct DynamicState {
42 | path_loaded: String,
43 | image: ImageBuffer, Vec>,
44 | }
45 |
46 | impl Default for CircleSketch {
47 | fn default() -> Self {
48 | Self {
49 | line_size: 1.0,
50 | grid_mul: 1.0,
51 | path: String::default(),
52 | have_image: false,
53 | scale_mul: 1.0,
54 | w: 0,
55 | h: 0,
56 | circles: 4,
57 | black_max: 5,
58 | rings: 20,
59 | spacing: 5.0,
60 | subdiv: 128,
61 | priority: false,
62 | invert: false,
63 | dstate: DynamicState::default(),
64 | }
65 | }
66 | }
67 |
68 | impl CircleSketch {
69 | fn load_image(&mut self) -> Result<(), ()> {
70 | let mut img = ImageReader::open(&self.path)
71 | .map_err(|e| ())?
72 | .decode()
73 | .map_err(|e| ())?
74 | .to_rgb8();
75 |
76 | let w2 = (img.width()as f64 * self.scale_mul) as u32;
77 | let h2 = (img.height()as f64 * self.scale_mul) as u32;
78 | self.w = w2;
79 | self.h = h2;
80 |
81 | let img = image::imageops::resize(
82 | &img,
83 | w2,
84 | h2,
85 | image::imageops::FilterType::CatmullRom,
86 | );
87 |
88 | self.dstate.image = img;
89 | self.dstate.path_loaded = self.path.clone();
90 | return Ok(());
91 | }
92 |
93 | fn draw(self: &mut CircleSketch, sketch: &mut Sketch, ctx: &mut Context)
94 | {
95 | let image = &self.dstate.image;
96 | let scale1 = f64::min(vsvg::Unit::Mm.convert_from(&vsvg::Unit::Px, sketch.width()) / image.width() as f64,
97 | vsvg::Unit::Mm.convert_from(&vsvg::Unit::Px, sketch.height()) / image.height() as f64);
98 | let circle_space = self.line_size * self.spacing;
99 |
100 |
101 | let mut flags: ImageBuffer, Vec> = ImageBuffer::from_fn(image.width(), image.height(), |x, y| {
102 | image::Luma([0u8])
103 | });
104 |
105 | let mut circles = Vec::new();
106 | let w = (image.width() as f64) * scale1;
107 | let h = (image.height() as f64) * scale1;
108 | for circle in 0..self.circles {
109 | let c = ctx.rng_point(0.0..w, 0.0..h);
110 | let r = self.rings as f64 * circle_space;
111 |
112 | circles.push((c, r));
113 | }
114 | for circle in 0..self.circles as usize {
115 | let (c, r) = circles[circle];
116 | for ring in 0..self.rings {
117 | //sketch.circle(c.x(), c.y(), (ring+1) as f64 * circle_space);
118 | let r = (ring+1) as f64 * circle_space;
119 | let mut prev = c + Point::new(r, 0);
120 | for i in 1..=self.subdiv {
121 | let angle = f64::to_radians((360.0 * i as f64) / (self.subdiv as f64));
122 | let p2: Point = c + Point::new(angle.cos(), angle.sin()) * r;
123 |
124 | let mut posp = (image.width() as f64 * (p2.x()/w), image.height()as f64 * (p2.y()/h));
125 | posp.0 = if posp.0 >= 0.0 {posp.0} else {(image.width() + 3) as f64};
126 | posp.1 = if posp.1 >= 0.0 {posp.1} else {(image.height() + 3) as f64};
127 |
128 | let pixel = image.get_pixel_checked(posp.0 as u32, posp.1 as u32).unwrap_or(&image::Rgb([255u8, 255u8, 255u8]));
129 | //let v = pixel_magnitude2(*pixel);
130 | let v = pixel.to_luma().0[0];
131 |
132 | let numf = if self.invert {
133 | v as f32 / 255.0
134 | } else {
135 | 1.0-(v as f32 / 255.0)
136 | };
137 | let need = (numf * self.black_max as f32) as i32;
138 |
139 | let num_have = if self.priority {
140 | circles[0..circle].iter().map(|x: &(Point, f64)| {
141 | if p2.distance(&x.0) < x.1 {
142 | 1
143 | } else {
144 | 0
145 | }
146 | }).sum()
147 | } else {
148 | circles.iter().enumerate().map(|(i, x)| {
149 | if i == circle {
150 | return 0;
151 | }
152 | if p2.distance(&x.0) < x.1 && p2.distance(&x.0) < p2.distance(&c){
153 | 1
154 | } else {
155 | 0
156 | }
157 | }).sum()
158 | };
159 |
160 | if need > num_have {
161 | sketch.line(prev.x(), prev.y(), p2.x(), p2.y());
162 | }
163 |
164 | prev = p2;
165 |
166 | }
167 | }
168 | }
169 |
170 | /*grid.build(sketch, |sketch, cell| {
171 | let p1 = cell.position;
172 | let p2 = p1 + Point::new(cell.size[0]*0.1, 0);
173 |
174 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
175 | let mg = pixel_magnitude2(*c1).isqrt();
176 |
177 | let W = mina.len();
178 | let a: i32 = mina[cell.row % W][cell.column % W];
179 | let d: i32 = dir[cell.row % W][cell.column % W];
180 |
181 |
182 |
183 | if 443-mg > ((443) * (a+1)) / 17 {
184 | *flags.get_pixel_mut(cell.column as u32, cell.row as u32) = Luma([d as u8; 1]);
185 | //sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
186 | }
187 | });*/
188 |
189 | }
190 | }
191 |
192 | fn pixel_magnitude2(p: Rgb) -> i32 {
193 | let c = p.channels();
194 | return c[0] as i32 * c[0] as i32 + c[1] as i32 * c[1] as i32 + c[2] as i32 * c[2] as i32;
195 | }
196 |
197 | type IPos2 = Vector2;
198 |
199 | fn pixel_to_vec32f(p: Rgb) -> Vector3 {
200 | return Vector3::new(p.0[0] as f32, p.0[1] as f32, p.0[2] as f32);
201 | }
202 |
203 |
204 |
205 | pub fn grid_cell(grid: f64, pos: IPos2) -> Vec2 {
206 | return Vec2::new(pos.x as f64 * grid, pos.y as f64 * grid);
207 | }
208 |
209 |
210 |
211 |
212 |
213 |
214 | impl App for CircleSketch {
215 | fn update(&mut self, sketch: &mut Sketch, ctx: &mut Context) -> anyhow::Result<()> {
216 | if self.path != self.dstate.path_loaded {
217 | match self.load_image() {
218 | Err(_) => {
219 | std::eprintln!("Failed to load image");
220 | self.have_image = false;
221 | }
222 | Ok(_) => {
223 | self.have_image = true;
224 | }
225 | }
226 | self.dstate.path_loaded = self.path.clone();
227 | }
228 | if self.dstate.image.is_empty() {
229 | eprintln!("No image");
230 | return Ok(());
231 | }
232 | sketch.scale(Unit::Mm);
233 | sketch.stroke_width( vsvg::Unit::Mm.convert_to(&vsvg::Unit::Px, self.line_size) );
234 |
235 | self.draw(sketch, ctx);
236 |
237 | Ok(())
238 | }
239 | }
240 |
241 | fn main() -> whiskers::prelude::Result {
242 | CircleSketch::runner()
243 | .with_page_size_options(PageSize::A5H)
244 | .with_layout_options(LayoutOptions::Center)
245 | .run()
246 | }
247 |
--------------------------------------------------------------------------------
/vsvg/simple/examples/circles2.rs:
--------------------------------------------------------------------------------
1 |
2 | use image::{GenericImageView, ImageBuffer, ImageReader, Luma, Pixel, Rgb};
3 | use kurbo::Vec2;
4 | use nalgebra::{vector, Vector2, Vector3};
5 | use serde;
6 | use std::result::Result;
7 | use vsvg::UNITS;
8 | use whiskers::prelude::*;
9 |
10 |
11 | #[sketch_app]
12 | struct CircleSketch {
13 | #[param(slider, min = 0.01, max = 5.0)]
14 | line_size: f64,
15 | grid_mul: f64,
16 | have_image:bool,
17 | scale_mul: f64,
18 | w: u32,
19 | h: u32,
20 |
21 | circles: usize,
22 | black_max: i32,
23 | rings: i32,
24 | #[param(slider, min = 0.1, max = 20.0)]
25 | spacing: f64,
26 |
27 | subdiv: i32,
28 |
29 | priority: bool,
30 | invert: bool,
31 |
32 |
33 |
34 | #[skip]
35 | #[serde(skip)]
36 | dstate: DynamicState,
37 | }
38 |
39 | #[derive(Default)]
40 | struct DynamicState {
41 | }
42 |
43 | impl Default for CircleSketch {
44 | fn default() -> Self {
45 | Self {
46 | line_size: 1.0,
47 | grid_mul: 1.0,
48 | have_image: false,
49 | scale_mul: 1.0,
50 | w: 0,
51 | h: 0,
52 | circles: 4,
53 | black_max: 5,
54 | rings: 20,
55 | spacing: 5.0,
56 | subdiv: 128,
57 | priority: false,
58 | invert: false,
59 | dstate: DynamicState::default(),
60 | }
61 | }
62 | }
63 |
64 | impl CircleSketch {
65 |
66 | fn draw(self: &mut CircleSketch, sketch: &mut Sketch, ctx: &mut Context)
67 | {
68 |
69 | let circle_space = self.line_size * self.spacing;
70 |
71 |
72 | let mut circles = Vec::new();
73 | let w = vsvg::Unit::Mm.convert_from(&vsvg::Unit::Px, sketch.width());
74 | let h = vsvg::Unit::Mm.convert_from(&vsvg::Unit::Px,sketch.height());
75 | for circle in 0..self.circles {
76 | let c = ctx.rng_point(0.0..w, 0.0..h);
77 | let r = self.rings as f64 * circle_space;
78 |
79 | circles.push((c, r));
80 | }
81 | for circle in 0..self.circles as usize {
82 | let (c, r) = circles[circle];
83 |
84 | let need = *ctx.rng_choice(&[1, 1, 1, 2]);
85 | for ring in 0..self.rings {
86 | //sketch.circle(c.x(), c.y(), (ring+1) as f64 * circle_space);
87 | let r = (ring+1) as f64 * circle_space;
88 | let mut prev = c + Point::new(r, 0);
89 | for i in 1..=self.subdiv {
90 | let angle = f64::to_radians((360.0 * i as f64) / (self.subdiv as f64));
91 | let p2: Point = c + Point::new(angle.cos(), angle.sin()) * r;
92 |
93 | /*let mut posp = (image.width() as f64 * (p2.x()/w), image.height()as f64 * (p2.y()/h));
94 | posp.0 = if posp.0 >= 0.0 {posp.0} else {(image.width() + 3) as f64};
95 | posp.1 = if posp.1 >= 0.0 {posp.1} else {(image.height() + 3) as f64};
96 | */
97 |
98 | //let v = pixel_magnitude2(*pixel);
99 | /*let v = pixel.to_luma().0[0];
100 |
101 | let numf = if self.invert {
102 | v as f32 / 255.0
103 | } else {
104 | 1.0-(v as f32 / 255.0)
105 | };
106 | let need = (numf * self.black_max as f32) as i32;*/
107 |
108 | let num_have = if self.priority {
109 | circles[0..circle].iter().map(|x: &(Point, f64)| {
110 | if p2.distance(&x.0) < x.1 {
111 | 1
112 | } else {
113 | 0
114 | }
115 | }).sum()
116 | } else {
117 | circles.iter().enumerate().map(|(i, x)| {
118 | if i == circle {
119 | return 0;
120 | }
121 | if p2.distance(&x.0) < x.1 && p2.distance(&x.0) < p2.distance(&c){
122 | 1
123 | } else {
124 | 0
125 | }
126 | }).sum()
127 | };
128 |
129 | if need > num_have {
130 | sketch.line(prev.x(), prev.y(), p2.x(), p2.y());
131 | }
132 |
133 | prev = p2;
134 |
135 | }
136 | }
137 | }
138 |
139 | /*grid.build(sketch, |sketch, cell| {
140 | let p1 = cell.position;
141 | let p2 = p1 + Point::new(cell.size[0]*0.1, 0);
142 |
143 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
144 | let mg = pixel_magnitude2(*c1).isqrt();
145 |
146 | let W = mina.len();
147 | let a: i32 = mina[cell.row % W][cell.column % W];
148 | let d: i32 = dir[cell.row % W][cell.column % W];
149 |
150 |
151 |
152 | if 443-mg > ((443) * (a+1)) / 17 {
153 | *flags.get_pixel_mut(cell.column as u32, cell.row as u32) = Luma([d as u8; 1]);
154 | //sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
155 | }
156 | });*/
157 |
158 | }
159 | }
160 |
161 | fn pixel_magnitude2(p: Rgb) -> i32 {
162 | let c = p.channels();
163 | return c[0] as i32 * c[0] as i32 + c[1] as i32 * c[1] as i32 + c[2] as i32 * c[2] as i32;
164 | }
165 |
166 | type IPos2 = Vector2;
167 |
168 | fn pixel_to_vec32f(p: Rgb) -> Vector3 {
169 | return Vector3::new(p.0[0] as f32, p.0[1] as f32, p.0[2] as f32);
170 | }
171 |
172 |
173 |
174 | pub fn grid_cell(grid: f64, pos: IPos2) -> Vec2 {
175 | return Vec2::new(pos.x as f64 * grid, pos.y as f64 * grid);
176 | }
177 |
178 |
179 |
180 |
181 |
182 |
183 | impl App for CircleSketch {
184 | fn update(&mut self, sketch: &mut Sketch, ctx: &mut Context) -> anyhow::Result<()> {
185 |
186 | sketch.scale(Unit::Mm);
187 | sketch.stroke_width( vsvg::Unit::Mm.convert_to(&vsvg::Unit::Px, self.line_size) );
188 |
189 | self.draw(sketch, ctx);
190 |
191 | Ok(())
192 | }
193 | }
194 |
195 | fn main() -> whiskers::prelude::Result {
196 | CircleSketch::runner()
197 | .with_page_size_options(PageSize::A5H)
198 | .with_layout_options(LayoutOptions::Center)
199 | .run()
200 | }
201 |
--------------------------------------------------------------------------------
/vsvg/simple/examples/mst.rs:
--------------------------------------------------------------------------------
1 |
2 | use image::{GenericImageView, ImageBuffer, ImageReader, Pixel, Rgb};
3 | use kurbo::Vec2;
4 | use nalgebra::{vector, Vector2, Vector3};
5 | use serde;
6 | use std::result::Result;
7 | use vsvg::UNITS;
8 | use whiskers::prelude::*;
9 |
10 | #[sketch_app]
11 | struct MSTImageSketch {
12 | #[param(slider, min = 0.01, max = 5.0)]
13 | line_size: f64,
14 | path: String,
15 | have_image: bool,
16 | #[param(min = 0.0, max = 100.0)]
17 | zero_dist_cost: f32,
18 | min_dist: bool,
19 | pr_mult: f32,
20 | #[param(slider, min = 0.01, max = 5.0)]
21 | pr_power: f64,
22 | #[skip]
23 | #[serde(skip)]
24 | dstate: DynamicState,
25 | }
26 |
27 | #[derive(Default)]
28 | struct DynamicState {
29 | path_loaded: String,
30 | image: ImageBuffer, Vec>,
31 | }
32 |
33 | impl Default for MSTImageSketch {
34 | fn default() -> Self {
35 | Self {
36 | line_size: 1.0,
37 | path: String::default(),
38 | zero_dist_cost: 0f32,
39 | pr_mult: 1f32,
40 | pr_power: 1f64,
41 | have_image: false,
42 | min_dist: false,
43 | dstate: DynamicState::default(),
44 | }
45 | }
46 | }
47 |
48 | impl MSTImageSketch {
49 | fn load_image(&mut self) -> Result<(), ()> {
50 | let mut img = ImageReader::open(&self.path)
51 | .map_err(|e| ())?
52 | .decode()
53 | .map_err(|e| ())?
54 | .to_rgb8();
55 |
56 | let img = image::imageops::resize(
57 | &img,
58 | img.width() / 4,
59 | img.height() / 4,
60 | image::imageops::FilterType::CatmullRom,
61 | );
62 |
63 | self.dstate.image = img;
64 | self.dstate.path_loaded = self.path.clone();
65 | return Ok(());
66 | }
67 | }
68 |
69 | fn pixel_magnitude2(p: Rgb) -> i32 {
70 | let c = p.channels();
71 | return c[0] as i32 * c[0] as i32 + c[1] as i32 * c[1] as i32 + c[2] as i32 * c[2] as i32;
72 | }
73 |
74 | type IPos2 = Vector2;
75 |
76 | fn pixel_to_vec32f(p: Rgb) -> Vector3 {
77 | return Vector3::new(p.0[0] as f32, p.0[1] as f32, p.0[2] as f32);
78 | }
79 |
80 |
81 | struct HeapPos {
82 | cost: f32,
83 | pos: IPos2,
84 | prev: IPos2,
85 | }
86 |
87 |
88 | impl PartialEq for HeapPos {
89 | fn eq(&self, other: &Self) -> bool {
90 | self.cost == other.cost
91 | }
92 | }
93 | impl PartialOrd for HeapPos {
94 | fn partial_cmp(&self, other: &Self) -> Option {
95 | return Some(self.cmp(other));
96 | }
97 | }
98 | impl Ord for HeapPos {
99 | fn cmp(&self, other: &Self) -> std::cmp::Ordering {
100 | return other.cost.total_cmp(&self.cost);
101 | }
102 | }
103 | impl Eq for HeapPos {
104 |
105 | }
106 |
107 | pub fn grid_cell(grid: f64, pos: IPos2) -> Vec2 {
108 | return Vec2::new(pos.x as f64 * grid, pos.y as f64 * grid);
109 | }
110 |
111 | impl App for MSTImageSketch {
112 | fn update(&mut self, sketch: &mut Sketch, _ctx: &mut Context) -> anyhow::Result<()> {
113 | if self.path != self.dstate.path_loaded {
114 | match self.load_image() {
115 | Err(_) => {
116 | std::eprintln!("Failed to load image");
117 | self.have_image = false;
118 | }
119 | Ok(_) => {
120 | self.have_image = true;
121 | }
122 | }
123 | self.dstate.path_loaded = self.path.clone();
124 | }
125 | if self.dstate.image.is_empty() {
126 | eprintln!("No image");
127 | return Ok(());
128 | }
129 | sketch.scale(Unit::Mm);
130 | sketch.stroke_width(self.line_size);
131 |
132 | let image = &self.dstate.image;
133 | let pw = vsvg::Unit::Mm.convert(sketch.width()) / image.width() as f64;
134 |
135 | let grid = Grid::from_cell_size([pw, pw])
136 | .columns(self.dstate.image.width() as usize)
137 | .rows(self.dstate.image.height() as usize);
138 | let mut nr = 0;
139 | /*grid.build(sketch, |sketch, cell| {
140 | let p1 = cell.position;
141 | let p2 = p1 + Point::new(cell.size[0], 0);
142 | if cell.column + 1 >= image.width() as usize {
143 | return;
144 | }
145 | let c1 = image.get_pixel(cell.column as u32, cell.row as u32);
146 | let c2 = image.get_pixel((cell.column + 1) as u32, cell.row as u32);
147 | if pixel_magnitude2(*c1) < pixel_magnitude2(*c2) {
148 | sketch.line(p1.x(), p1.y(), p2.x(), p2.y());
149 | }
150 | if nr < 8000000 {
151 | nr += 1;
152 | }
153 | });*/
154 | let mut heap: std::collections::BinaryHeap = std::collections::BinaryHeap::new();
155 | let mut processed: std::collections::HashSet = std::collections::HashSet::new();
156 | let DV = [
157 | IPos2::new(-1, 0),
158 | IPos2::new(1, 0),
159 | IPos2::new(0, 1),
160 | IPos2::new(0, -1),
161 | IPos2::new(1, -1),
162 | IPos2::new(-1, -1),
163 | IPos2::new(1, 1),
164 | IPos2::new(-1, 1),
165 | ];
166 | let mut p0 = IPos2::new(0, 0);
167 | let mut best = 100_f32;
168 | for i in 0..image.height() {
169 | for j in 0..image.width() {
170 | let p = *image.get_pixel(j, i);
171 | let sum = pixel_to_vec32f(p).magnitude();
172 | if sum < best {
173 | p0 = IPos2::new(j as i32, i as i32);
174 | best = sum;
175 | }
176 | }
177 | }
178 |
179 | heap.push(HeapPos {
180 | cost: 0.0,
181 | pos: p0,
182 | prev: p0,
183 | });
184 | while let Some(front) = heap.pop() {
185 | if processed.contains(&front.pos) {
186 | continue;
187 | }
188 | processed.insert(front.pos);
189 |
190 | let current_pix =
191 | pixel_to_vec32f(*image.get_pixel(front.pos.x as u32, front.pos.y as u32));
192 |
193 | let pr = 1f64 - current_pix.magnitude() as f64/((3*255*255) as f64).sqrt();
194 | if !_ctx.rng_weighted_bool(( self.pr_mult as f64 * pr.powf(self.pr_power)).clamp(0.0, 1.0)) {
195 | continue;
196 | }
197 |
198 | let p1 = grid_cell(pw, front.pos);
199 | let p2 = grid_cell(pw, front.prev);
200 |
201 |
202 | sketch.line(p1.x, p1.y, p2.x, p2.y);
203 | for dir in DV {
204 | let target = front.pos + dir;
205 |
206 | if target.x < 0
207 | || target.y < 0
208 | || !image.in_bounds(target.x as u32, target.y as u32)
209 | {
210 | continue;
211 | }
212 | let target_pixel =
213 | pixel_to_vec32f(*image.get_pixel(target.x as u32, target.y as u32));
214 | let mut dist = ((target_pixel - current_pix).magnitude() + self.zero_dist_cost) * (dir.dot(&dir) as f32).sqrt();
215 | if self.min_dist {
216 | dist += front.cost;
217 | }
218 | heap.push(HeapPos {
219 | cost: dist /*+ front.cost*/,
220 | pos: target,
221 | prev: front.pos,
222 | })
223 | }
224 | }
225 |
226 | Ok(())
227 | }
228 | }
229 |
230 | fn main() -> whiskers::prelude::Result {
231 | MSTImageSketch::runner()
232 | .with_page_size_options(PageSize::A5H)
233 | .with_layout_options(LayoutOptions::Center)
234 | .run()
235 | }
236 |
--------------------------------------------------------------------------------
/vsvg/simple/examples/pattern_1.rs:
--------------------------------------------------------------------------------
1 | use egui::lerp;
2 | use vsvg::UNITS;
3 | use whiskers::prelude::*;
4 |
5 | #[sketch_app]
6 | struct HexGridSketch {
7 | #[param(min = 0.01, max = 100.0)]
8 | line_size: f64,
9 | is_pointy_orientation: bool,
10 | #[param(slider, min = 2, max = 100)]
11 | columns: usize,
12 | #[param(slider, min = 2, max = 100)]
13 | rows: usize,
14 | #[param(slider, min = 0.0, max = 200.0)]
15 | spacing: f64,
16 | #[param(slider, min = 0.0, max = 100.0)]
17 | cell_size: f64,
18 | #[param(slider, min = 0.0, max = 1.0)]
19 | tree_h: f64,
20 | #[param(slider, min = 0.0, max = 90.0)]
21 | angle: f64,
22 |
23 | #[param(slider, min = 0.0, max = 360.0)]
24 | angle2: f64,
25 | }
26 |
27 | impl Default for HexGridSketch {
28 | fn default() -> Self {
29 | Self {
30 | line_size: 1.0,
31 | columns: 5,
32 | rows: 5,
33 | spacing: 0.0,
34 | is_pointy_orientation: false,
35 | cell_size: 40.0,
36 | tree_h: 0.7,
37 | angle: 45.0,
38 | angle2: 0.0,
39 | }
40 | }
41 | }
42 |
43 | impl App for HexGridSketch {
44 | fn update(&mut self, sketch: &mut Sketch, _ctx: &mut Context) -> anyhow::Result<()> {
45 | sketch.stroke_width(self.line_size);
46 |
47 | let grid = if self.is_pointy_orientation {
48 | HexGrid::with_pointy_orientation()
49 | } else {
50 | HexGrid::with_flat_orientation()
51 | };
52 |
53 | sketch.scale(Unit::Mm);
54 |
55 | grid.cell_size(self.cell_size)
56 | .columns(self.columns)
57 | .rows(self.rows)
58 | .spacing(self.spacing)
59 | .build(sketch, |sketch, cell| {
60 | let b = Point::new(0.0, 0.0); //cell.center;
61 | let top = b + Point::new(0, -self.cell_size * self.tree_h);
62 | let mut points = vec![b, top];
63 |
64 | for i in 0..3 {
65 | let frac = i as f64 / 3 as f64;
66 | let start = Point::new(0, top.y() - (top.y() * 0.5) * frac);
67 | points.push(start);
68 | let w = top.y().abs() * lerp(3.0..=10.0, 0.1);
69 | let br_h = w / self.angle.to_radians().tan();
70 | points.push(start + Point::new(-w, br_h));
71 | points.push(start);
72 | points.push(start + Point::new(w, br_h));
73 | points.push(start);
74 | }
75 | sketch.push_matrix();
76 |
77 |
78 | sketch.translate(cell.center.x(), cell.center.y());
79 | sketch.rotate_around(
80 | Angle::from_deg(self.angle2),
81 | 0.0,
82 | top.y() * 0.5,
83 | );
84 |
85 | sketch.polyline(points, true).pop_matrix();
86 | //sketch.add_path(cell);
87 | });
88 |
89 | Ok(())
90 | }
91 | }
92 |
93 | fn main() -> Result {
94 | HexGridSketch::runner()
95 | .with_page_size_options(PageSize::A5H)
96 | .with_layout_options(LayoutOptions::Center)
97 | .run()
98 | }
99 |
--------------------------------------------------------------------------------
/vsvg/simple/examples/snowfl.rs:
--------------------------------------------------------------------------------
1 | // Inspired by the approach used by revdancatt https://revdancatt.com/penplotter/036-Snowflakes/
2 |
3 | use std::cmp::min;
4 |
5 | use egui::lerp;
6 | use vsvg::UNITS;
7 | use whiskers::prelude::*;
8 |
9 | #[sketch_app]
10 | struct HexGridSketch {
11 | #[param(min = 0.01, max = 100.0)]
12 | line_size: f64,
13 | is_pointy_orientation: bool,
14 | #[param(slider, min = 2, max = 100)]
15 | columns: usize,
16 | #[param(slider, min = 2, max = 100)]
17 | rows: usize,
18 | #[param(slider, min = 0.0, max = 200.0)]
19 | spacing: f64,
20 | #[param(slider, min = 0.0, max = 100.0)]
21 | cell_size: f64,
22 | #[param(slider, min = 0.0, max = 1.0)]
23 | tree_h: f64,
24 | #[param(slider, min = 0.0, max = 90.0)]
25 | angle: f64,
26 |
27 | #[param(slider, min = 0.0, max = 360.0)]
28 | angle2: f64,
29 | }
30 |
31 | impl Default for HexGridSketch {
32 | fn default() -> Self {
33 | Self {
34 | line_size: 1.0,
35 | columns: 5,
36 | rows: 5,
37 | spacing: 0.0,
38 | is_pointy_orientation: false,
39 | cell_size: 40.0,
40 | tree_h: 0.7,
41 | angle: 45.0,
42 | angle2: 0.0,
43 | }
44 | }
45 | }
46 |
47 | impl App for HexGridSketch {
48 | fn update(&mut self, sketch: &mut Sketch, _ctx: &mut Context) -> anyhow::Result<()> {
49 | sketch.stroke_width(self.line_size);
50 |
51 | let grid = if self.is_pointy_orientation {
52 | HexGrid::with_pointy_orientation()
53 | } else {
54 | HexGrid::with_flat_orientation()
55 | };
56 |
57 | sketch.scale(Unit::Mm);
58 |
59 | grid.cell_size(self.cell_size)
60 | .columns(self.columns)
61 | .rows(self.rows)
62 | .spacing(self.spacing)
63 | .build(sketch, |sketch, cell| {
64 | let b = Point::new(0.0, 0.0); //cell.center;
65 | let top = b + Point::new(0, -self.cell_size * self.tree_h);
66 |
67 | sketch.push_matrix();
68 |
69 | sketch.translate(cell.center.x(), cell.center.y());
70 | sketch.rotate_around(Angle::from_deg(self.angle2), 0.0, 0.0);
71 |
72 | let size: f64 = self.tree_h * self.cell_size;
73 | let steps = _ctx.rng_range(2..5);
74 | let mut branches = vec![(0.0, 0); steps];
75 | let shape = _ctx.rng_range(0..1);
76 | let branch_w = vec![(80.0, 0), (20.0, 1), (10.0, 2), (10.0, 3)];
77 | let linec = {
78 | if _ctx.rng_weighted_bool(0.10) {
79 | _ctx.rng_range(2..4)
80 | } else {
81 | 1
82 | }
83 | };
84 |
85 | for b in 0..steps {
86 | let pos = size * ((1 + b) as f64) / (steps as f64 + 1.0);
87 | let mut maxl = size;
88 | if shape == 0 {
89 | maxl = f64::min(size * 0.3, pos);
90 | }
91 | let l = _ctx.rng_range(0.3..1.3) * maxl;
92 | let t = *_ctx.rng_weighted_choice(&branch_w);
93 | branches[b] = (l, t);
94 | }
95 |
96 | if !self.is_pointy_orientation {
97 | sketch.rotate(Angle::from_deg(30.0));
98 | }
99 |
100 | for _i in 0..3 {
101 | sketch.rotate(Angle::from_deg(60.0));
102 |
103 | if linec == 1 {
104 | sketch.line(0, -size, 0, size);
105 | } else if linec == 2 {
106 | let w = 0.05 * size;
107 | sketch.line(-w, -size, -w, size);
108 | sketch.line(w, size, w, -size);
109 | } else {
110 | for i in 0..linec {
111 | let w = 0.1 * size;
112 | let p = i as f64 * w / ((linec - 1) as f64) - 0.5 * w;
113 | let down = if i % 2 == 0 {1f64} else {-1f64};
114 | sketch.line(p, -size * down, p, size * down);
115 |
116 |
117 | }
118 | }
119 |
120 | }
121 | for _i in 0..6 {
122 | sketch.rotate(Angle::from_deg(60.0));
123 | //sketch.line(0, 0, 0, size);
124 | for b in 0..steps {
125 | let pos = size * ((1 + b) as f64) / (steps as f64 + 1.0);
126 | let (l, t) = branches[b];
127 | if t == 0 {
128 | sketch.line(
129 | -f64::sin(60_f64.to_radians()) * l,
130 | pos + f64::cos(60_f64.to_radians()) * l,
131 | 0,
132 | pos,
133 | );
134 | sketch.line(
135 | 0,
136 | pos,
137 | f64::sin(60_f64.to_radians()) * l,
138 | pos + f64::cos(60_f64.to_radians()) * l,
139 | );
140 | } else if t == 1 {
141 | sketch.line(
142 | -f64::sin(60_f64.to_radians()) * l,
143 | pos - f64::cos(60_f64.to_radians()) * l,
144 | 0,
145 | pos,
146 | );
147 | sketch.line(
148 | 0,
149 | pos,
150 | f64::sin(60_f64.to_radians()) * l,
151 | pos - f64::cos(60_f64.to_radians()) * l,
152 | );
153 | } else if t == 2 {
154 | sketch.circle(0, pos, f64::min(l, 0.15 * size));
155 | } else if t == 3 {
156 | let l2 = f64::min(l, 0.15 * size);
157 | sketch
158 | .push_matrix()
159 | .translate(0, pos)
160 | .polyline(
161 | (0..6).map(|i| {
162 | let a = ((60 * i) as f64).to_radians();
163 | Point::new(a.sin() * l2, a.cos() * l2)
164 | }),
165 | true,
166 | )
167 | .pop_matrix();
168 | }
169 | }
170 | }
171 |
172 | sketch.pop_matrix();
173 | //sketch.add_path(cell);
174 | });
175 |
176 | Ok(())
177 | }
178 | }
179 |
180 | fn main() -> Result {
181 | HexGridSketch::runner()
182 | .with_page_size_options(PageSize::A5H)
183 | .with_layout_options(LayoutOptions::Center)
184 | .run()
185 | }
186 |
--------------------------------------------------------------------------------
/vsvg/simple/readme.md:
--------------------------------------------------------------------------------
1 | Running: `cargo run --example `
--------------------------------------------------------------------------------
/vsvg/simple/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | println!("See examples !");
3 | }
4 |
--------------------------------------------------------------------------------