Closed sergstetsuk closed 6 years ago
Neat! I'd be interested to hear what about my branch didn't work well for you -- perhaps I can add features.
I'm currently in the middle of a big refactor on my fork's master branch. My ultimate goal is to handle fills in complicated regions automatically and without any jump stitches. The code would instead do running stitches around the outside to get from one section of the fill to the next. After that, I'll add options to do underlay, so that the code can underlay and fill an entire shape automatically.
Glad to hear. I took your work. It is much better than stesie's one. So about your branch: It has some troubles too.
I'm glad you've found my branch useful! I'm hoping we can turn this into a usable alternative to paid applications.
I can see that some of your issues are because we're using the plugin differently. It might help if I explain how I do it. Ultimately, I hope to write all this up into a README in my fork.
First of all, I have inkscape-embroidery output CSV, which can be consumed directly by Embroidermodder2. There's a script in there under experimental/python/converter
that can convert CSV to PES for Brother machines (I have an SE400).
I've modified my branch extensively to allow me to set all of the embroider parameters as XML attributes on the <svg:path>
tags. That way I can set a custom fill angle for each fill region, for example. Once I have all of my shapes set up the way I want, I run the plugin on the whole thing, embroidering everything at once, and saving to a .CSV file. Then I hit ctrl-Z -- I don't save the paths the script generates.
I also try to avoid using the traveling salesman code. It's not very good at reducing jump stitches, and it's random. I much prefer to specify the exact path that the needle follows as it stitches everything out. I use the latest beta version of inkscape which contains the "object details" palette. That gives me a list of all objects in every layer, so I can reorder them as needed. I wrote a "reorder" plugin that lets me select objects in order in inkscape and then restack them in that order.
Now, for your questions/issues, I have some info that might help:
My toolchain is something like this. Get a picture. convert to embroidery using right filling angle for each element or group of elements. Fix corners and other staff in the generated SVG. Convert with svg2pes. Check in Embroiderymodder2.
Pardon, I misspoke. I meant to say, spaces are preferred for python.
inkscape-embroidery
directly into a PES.I can see the advantage to using "real" sizes if you're editing stitches manually, but I never do that. If the code didn't generate it how I wanted, either I need to modify the shapes, or I fix the code to meet my expectations.
As to using XML attributes and defaulting to the ones from the dialog: that's exactly what I do. But I almost never modify the settings in the dialog -- I have a keystroke (ctrl+e) bound to run the embroider extension without popping up the dialog first. In practice I specify all params on all of my objects via XML attributes. That way I'm sure that if I reload a file months from now, it'll stitch out the same.
If you use 4 spaces indent you should change PyEmb.py file to have 4 spaces instead of tabs too.
Okay, my PyEmb.py
is fixed. Just hadn't gotten there before now :)
Yeah, we're probably getting to the point where we should find another place to discuss. I would mention that I only have sporadic availability to work on this project due to other demands on my time, so it's quite possible I may go dark at some point. I'm excited to have someone else working on this codebase though!
As to the sharp corner issue: At this point, I never use the feature that converts a shape's stroke to zig-zag. Instead I use the new "satin column" feature I added. This lets you carefully control how the stitches go around the corner to avoid the issue where corners end up with sparse stitching.
As to new file formats: I still feel like libembroidery is the way to go here. It has an excellent internal representation of stitches and it has a ton of formats already built in -- basically every machine embroidery format currently or previously in the market. Adding a new one to libembroidery would be preferable to writing a svg -> file converter, IMO.
The reason I like to work with 10 pixels per millimeter is that pretty much every reference I've found as I've learned machine embroidery uses millimeters. I think in millimeters as I design. I need to be able to easily measure objects on screen so that I can get my stitching right. Clearly what we need here is for pixels_per_millimeter
to be an option the user can specify!
And yes, I use the params filter I created to set the XML attributes on objects quickly. It's still pretty clunky. The alternative is to hit control-shift-X to pull up inkscape's builtin XML editor.
I had a chance to look at all of your changes from my branch. I see you removed the hatch_fills
option -- thank you! I kept meaning to do that. I'm not sure what the author wanted with that but it's not useful and looks ugly.
Good idea, changing everything from pixels to millimeters. Once we add the ability for the user to set pixels_per_millimeter
, I'll be able to merge your chagnes into my branch. I can't do it yet because it would break all of my existing projects (10+ designs).
Wow, lots of stuff here. I've also done a ton of work in my fork, and I'm not sure how possible it would be to merge yours with mine. :(
I did a huge refactor to have one class for each patch type. I added an algorithm to automatically route stitching for a fill region by traveling around the edge of the region. I entirely rewrote Params to have a GUI that shows existing settings for the selected shape. It also includes support for presets.
I'm now in the process of writing a detailed README, and once I finish, I'm going to call it version 1.0.
I see. Will try to examine and incorporate your changes to my branch. Today I tried to install plugin on Windows machine. It's a bit tricky. You can take windows related piece of installation instruction from my fork's README.md.
In your latest version I have "No module named backports.functools_lru_cache" error. Which module is needed? I can disable @cache related code and it seems to work. Could you open issues on your fork? Where can I find satin column and simple zigzag options now? Found! It is shown only for appropriate paths (with no fill at all)
hey, since both of you are very active wrt. inkscape-embroidery extension, opposed to me (for me it wasn't more than a weekend project to hack on) ... I'd happily start an organisation account here on github and move this repository to there, adding both of you as owners. Then you could merge and update as you see fit.
Would that help? Are there better options?
@stesie Hi!
TBH, I'm happy enough to stick with my own fork for now. Now that I'm back from vacation, I'm probably going to be significantly less active. I've also implemented the vast majority of the features I want. Thanks though :)
@sergstetsuk Re backports.functools_lru_cache
, it's this: https://pypi.python.org/pypi/backports.functools_lru_cache/1.3
As you've seen, it'll run without caching -- although I'd wager it's fairly slow for more complex shapes. I'll add a fallback to a noop function if backports.functools_lru_cache
can't be imported.
@sergstetsuk, I am interested in your ideas. Can we work together to merge your changes with @lexelby's? I would like to use real dimensions. I also like his use of XML attributes. I would love to see other stitch types, etc. as options (settable by XML attributes). My interests lie somewhere in https://github.com/treveradams/libpes/issues/1. It sounds like we have some overlapping goals.
I would like to figure out how to fix an error similar to http://stackoverflow.com/questions/20833344/fix-invalid-polygon-python-shapely as it hits me with every svg I am trying so that I cannot tell if the plugin will even work for me.
@treveradams Real dimentions are already possible. You should just set correct value for "pixels per mm" parameter i.e. "pixels/stitch". For real dimensions it will be 3.54 px/stitch = 90 px/inch / 2.54 mm/inch / 10 stitches/mm (taking to account Incscape's default pixel density). If you use custom density (for example 10 px/mm) than you shold use 1 px/stitch value. Sure I'd like to help you whatever I can. But my branch is almost a full copy of @lexelby. There are just some little improvements.
Ah, it appeared to me yours as a fork from @stesie not @lexelby. One problem I am having, which is impeding me working on this, is that every SVG I am trying (don't have any of my own yet) such as https://upload.wikimedia.org/wikipedia/en/a/a4/Flag_of_the_United_States.svg and http://www.freepik.com/free-vector/coloured-eagle-design_952146.htm#term=eagle&page=1&position=13 either have holes or problems like TopologyException: Input geom 1 is invalid: Self-intersection at or near point 290.59255118048708 224.16407805209684 at 290.59255118048708 224.16407805209684. I am trying to figure that out as I would love to use this.
@sergstetsuk, which of your branches is closes to @lexelby and (maybe most important) which is the one you will be continuing development on?
I was thinking of something along the lines of the following (untested) code being added:
#@cache
def get_embroider_attribute(self, attribute_name):
attributes = simplestyle.parseStyle(self.node.get("embroidery:settings"))
if (attributes not in attributes):
return None
value = attributes[attribute_name]
if value == 'none':
return None
return value
#@cache
def set_embroider_attribute(self, attribute_name, value):
attributes = []
attributes = simplestyle.parseStyle(self.node.get("embroidery:settings"))
style[style_name] = value
if value == 'none':
return None
node.attrib["embroidery:settings"] = simplestyle.formatStyle(attributes)
return value
Then things such as stitch length, stitch density, stitch angle, underlay related things, fill type, etc. could all be applied per object, which according to many of the design sites I have been looking at, is highly recommended (different stitch directions in different areas of the design, not the same color/part).
This would not replace the general options, they will still exist, but would be overridden by the per object options.
There appear to be at least 5 main underlay layouts so the values within the attribute might have the following names: underlay-type: contour, parallel, perpendicular, zig-zag, double-zig-zag, lattice, center-run (all but double can be seen https://embroideres.com/forum/blogs/entry/24-underlay-types-digitizing-tips/) underlay-angle underlay-row-spacing row-spacing fill-type (likely to just be satin for now) stitch-minimum-length stitch-maximum-length stitch-trim-minimum-length stitch-collapse-maximum-length already-stitched (i.e. true or false, this would be for paths that should be treated directly as stitches per https://github.com/frno7/libpes/blob/master/tools/pes-to-svg-emb.c)
It appears that underlays can be stacked in some other software as well, so underlay may be iterative. Not sure how to deal with angle/rowspacing in the case.
My master is more improved.
3.54? Shouldn't that be 25.4 or 2.54? or 10? I thought almost all, if not all, embroidery formats were 10 stitches max / mm, or better said, that their numbers were of that resolution. I have just created a pull request that hopefully gives you an idea of what I am wanting to add. I would love feed back.
Sorry, I just realized that the make file wasn't installing the params module. You already doing what I was wanting to do. Sorry for the noise.
Yes, 10 stitches/mm. And yes 3.54 value for (pixels per mm). As I mentioned early the parameter's caption is wrong. It must be named something like "number of stitches per 10 pixels". For density 10px/mm it will be still 10 stitches per 10 px. But for real sized pictures, where default Inkscape's density is 90 px/in you will have 90/2.54/10 = 3.54
Hi, @treveradams! Welcome to the project! Sorry I'm somewhat late to the party here -- my availability for working on this project tends to be in fits and starts.
First off, I think a good number of your questions can be answered in my docs branch: https://github.com/lexelby/inkscape-embroidery/blob/docs/README.md
It's incomplete as yet, but it should give you an idea of how I go about using inkscape-embroidery to produce actual PES files.
The "invalid geometry" thing can be tricky. What you're looking for is a self-intersection, that is, the edge of the shape crosses over itself. Looking at your shape, you probably don't see any self-intersections, right? Chances are one of the corners has an extremely tiny loop instead of being an actual corner.
One thing that might work to quickly eliminate loops like this is to use Inkscape's "simplify" command (ctrl+l by default). Of course, if that smooths your geometry more than you find acceptable, then that's no good.
Another way to detect this kind of thing is to look for spurious extra vertexes. Select your shape in the Node Editor tool and start drag-selecting each vertex, one at a time. Look down at the status bar at the bottom and see how many points are selected. If you see more than you expected, then there may be some doubled-up vertices with a very tiny self-intersection in there.
My latest master branch is converted over to use millimeters for all parameters, with a customizable "pixels per millimeter" setting in the main Embroider extension dialog. I set mine to 10 and use a 1000x1000 pixel canvas, giving me exactly the embroiderable area on my Brother SE400 (10x10cm, 4x4in).
My master branch also contains a GUI-based dialog I wrote for setting parameters for objects such as underlay type, stitch length, row spacing, etc. As you said, the recommended practice is to specify parameters for every object, and that's exactly the workflow I use. The GUI Params extension makes it easy to do this.
The README in my docs branch addresses how to deal with holes in your shapes: convert each into a shape that has no hole by cutting a tiny channel from the exterior to the interior. I do this by drawing a line with a stroke width of 0.1, Path -> Stroke to Path, then select that path and my fill area and use Path -> Difference (ctrl-minus). My algorithm tidily hides any traversal along the narrow channel amongst the neighboring fill rows, making it almost undetectable.
That said, I've been watching what @sergstetsuk is up to with trying to hide travel stitches in areas that will be embroidered later. I tried to envision a similar algorithm and just couldn't come up with a reasonable algorithm that I was convinced would work on all shapes and complete in a reasonable amount of time. I have yet to review his latest work, though.
@sergstetsuk with regard to the cache decorator, you should be able to resolve the exceptions by running pip install backports.functools_lru_cache
. The caching is not absolutely critical, but it saves on calculations that would otherwise be performed many times during each embroidery run.
I finished up my README and merged it into my master branch. Please let me know if anything is unclear!
@lexelby Thanks about lru_cache hint. I couldn't figure out how should I install it. Now I can uncomment cached operations. It seems it works much faster now.
@lexelby can you check such an issue in autofill algorithm? http://i.piccy.info/i9/9592cff25f34b946c5006259f9219f92/1485157157/29274/1111291/Zn_mok_ekranu_2017_01_23_09_37_33.png
@sergstetsuk It's hard to tell what might be wrong just from that picture. Can you post the SVG?
@lexelby It seems to be the issue in "maximum fill stitch len" parameter value. issue.zip
@sergstetsuk
A couple of things are going on in this SVG file. Some of the params are kind of not what I would expect and you're hitting some edge-cases in my code.
First of all, the M is pretty narrow, just around 5mm (assuming you're using 3.54 pixels per millimiter still?). Satin might work better.
Second, your max stitch length is quite big: 20mm. With staggers set to 1 like you have it, that's essentially going to result in satin. This is also where you're running into a couple of edge cases / bugs. First off, the fill region isn't being properly broken into runs because of the code in AutoFill.is_same_run:
def is_same_run(self, segment1, segment2):
if shgeo.Point(segment1[0]).distance(shgeo.Point(segment2[0])) > self.max_stitch_length:
return False
if shgeo.Point(segment1[1]).distance(shgeo.Point(segment2[1])) > self.max_stitch_length:
return False
return True
This code is really just a heuristic and it doesn't work well when the max stitch length is huge compared to the path you're filling.
So yes, AutoFill isn't handling this case well, but I think you might've meant to set max_stitch_length
to 2mm instead of 20?
@lexelby I am using @sergstetsuk branch. I see that spacing and zig-zag spacing is only available in the embroider part. It is not in the params. I think this should be available in both, params overriding if non-zero/present.
@sergstetsuk I don't seem to be able to get underlays to work with sergefill. Is this supposed to be this way?
I am sorry it takes me a while to get back to you all. I am learning how to design as I do this and I have other things which also demand my time. (I am sure the same can be said for both of you. Maybe not the design part.)
Is it possible to make these work if you know a hole is a hole? Can there be such an option? Think text inside another object. You would want to difference the text from the original and then put the text back.
@treveradams I'm not sure what you mean about (row?) spacing and zig-zag spacing. They're available in the Params ui. Here's where zigzag_spacing_mm
is defined for SatinColumn, for example: https://github.com/sergstetsuk/inkscape-embroidery/blob/master/embroider.py#L1229.
SergFill doesn't support underlay; only my AutoFill. See SergFill's implementation: https://github.com/sergstetsuk/inkscape-embroidery/blob/master/embroider.py#L1081.
Is it possible to make these work if you know a hole is a hole?
I'm not sure what you mean here, but here's my recommendation on how to handle holes with AutoFill: https://github.com/lexelby/inkscape-embroidery/#autofill
It's not ideal, but it does work. Ultimately I hope to design a new auto-fill algorithm that handles holes automatically. As far as I can tell, in order to properly handle all kinds of regions with (potentially multiple) holes, an algorithm would need to have recursion/backtracking. I've been thinking through how to do this but it's slow going.
As for text inside a fill region, I wouldn't recommend trying to treat the letters as holes. Unless your text is very large, it will be most legible if you render it as satin stitch instead of fill. You can do satin stitch right on top of fill stitch, as in the big "CPL" in this patch: https://github.com/lexelby/inkscape-embroidery/blob/master/images/patches/clinton_poker_league.jpg. Satin-on-fill seems to be a quite common technique.
If you try to do a fill region with the text cut out as holes and then fill the text in with a different thread color, I'm pretty sure it won't work well. You'll find that the natural distortion you get in all machine embroidery will cause gaps of the underlying fabric to show through between the fill and the letters. Plus, you'll have a lot of trouble trying to do the little tiny bits of fill inside loops in the text such as the hole in an "O" or even the crook inside a "J". I'm not saying it's not possible to make it work, but it's going to be a lot of unnecessary trouble when satin-on-fill produces a good result much more easily.
I am sorry it takes me a while to get back to you all. I am learning how to design as I do this and I have other things which also demand my time. (I am sure the same can be said for both of you. Maybe not the design part.)
No sweat at all. Conversations over the course of weeks are about the speed I can handle right now :)
@lexelby Do you think you can do a section in your README on text? I have been having a difficult time with that.
@sergstetsuk It seems that once autofill is set, it cannot be changed using params to serge fill.
Sure, I'll see if I can find the time to add some docs on text. Text has been by far the most time-consuming part of every design I've done so far. A couple tips while I'm here:
@treveradams SergFill works when Manual fill is enabled. You shold try disable Autofill and enable ManualFill. This is because of gui implementation. It is supposed AutoFill ON or OFF only. GUI need refactoring for multiple fill algorithm support (as well as multiple border and satin algos in future).
Underlay is really not implemented in SergFill. It is a todo item if algorithm is accepted at all. It's just yet another fill 90 degrees rotated and with rowspacing x 3.
What Flavour of linux are you using?
Sometimes the default filling direction is not the best one. User may use custom filling angle with this patch