inkstitch / pyembroidery

libembroidery/EmbroideryFormats converted to python
MIT License
71 stars 28 forks source link

Ensure good compatability with InkStitch #17

Closed tatarize closed 5 years ago

tatarize commented 6 years ago

Inkstitch Thread:

This is a subset so it's fine.

Inkstitch StitchPlan

Inkstitch ColorBlock:

Inkstitch Stitch:

Inkstitch Patch:

Some of this is arranging code to feed into libembroidery. Very little does actual work.

def write_embroidery_file(file_path, stitch_plan, svg):
    origin = get_origin(svg)

    pattern = libembroidery.embPattern_create()

    for color_block in stitch_plan:
        add_thread(pattern, make_thread(color_block.color))

        for stitch in color_block:
            if stitch.stop:
                # This is the start of the extra color block added by the
                # "STOP after" handler (see stitch_plan/stop.py).  Assign it
                # the same color.
                add_thread(pattern, make_thread(color_block.color))

            flags = get_flags(stitch)
            libembroidery.embPattern_addStitchAbs(pattern, stitch.x - origin.x, stitch.y - origin.y, flags, 1)

    libembroidery.embPattern_addStitchAbs(pattern, stitch.x - origin.x, stitch.y - origin.y, libembroidery.END, 1)

    # convert from pixels to millimeters
    libembroidery.embPattern_scale(pattern, 1/PIXELS_PER_MM)

    # SVG and embroidery disagree on the direction of the Y axis
    libembroidery.embPattern_flipVertical(pattern)

    libembroidery.embPattern_write(pattern, file_path)
tatarize commented 6 years ago

Inkstitch defect: conceptually, patches have points not not stitches.

Inkstitch -> Patches -> StitchPlan(ColorBlock) -> LibEmbroidery

Requires ability to implement, trim_after, stop after, and take in list of points with x, y properties easily.

lexelby commented 6 years ago

Think of Patch as more of a middle state inside Ink/Stitch, as it's still building its stitch plan. I wouldn't recommend trying to map Patch into a data structure in pyembroidery.

tatarize commented 6 years ago

What's your highest level not doing actually work state? Is basically just data you could send to something like pyembroidery? I mean patches are easy to have pyembroidery take in a bunch of points and commands to stop_after, trim_after. It basically does that now flagged with EmbPattern.BREAK commands.

lexelby commented 6 years ago

Well, as it stands now, it creates everything up to and including a sequence of stitches, jumps, stops, and trims. When we were discussing pyembroidery originally, I hadn't really envisioned it taking over figuring out where to put jumps and trims and whatnot.

I understand where you're coming from, when you suggest that pyembroidery should handle lower level stuff like that, but I'm not convinced. Users of Ink/Stitch are going to want me to continue adding features (e.g. frame-out) and I'd like the flexibility to implement that kind of stuff directly without waiting for code changes in pyembroidery.

I like the way libembroidery handles it now: it takes the low-level commands and writes them out in the chosen binary format. It needs the addition of SEQUIN and STOP support, but other than that, the model seems good to me. I'd like to avoid moving large swathes of functionality from Ink/Stitch into pyembroidery.

tatarize commented 6 years ago

I can provide much lower level stuff too. But, without consistency of input they will get brittle. Some formats won't write properly if the commands aren't in the right order per se. And it only needs to handle some of the higher level stuff. At a minimum the same stuff libembroidery does with breaking the long stitches into smaller ones and breaking the long moves into smaller ones.

Things like frame_eject wouldn't really be needed, or flagging it to do the tie-on tie-off stuff.

lexelby commented 6 years ago

Ah, I understand. Yes, I definitely feel that pyembroidery is the best place to handle things like splitting stitches that are longer than 12.1mm, for example.

Tie-off is tough. It'd be cool if I could just tell pyembroidery to tie off a given stitch. But what would you have it do? Right now, here's what Ink/Stitch does for a tie-off:

  1. look back at the last few stitches and construct a path from them
  2. do running stitch back along that path at 0.3mm per stitch for 2 stitches
  3. do running stitch forward along that path to get to the original end point

It's important that the tie stitches are hidden inside the stitches that led up to that point, rather than just being in some random direction that potentially sticks off the side of the design. My understanding is that just doing 3-5 stitches in place isn't good enough to tie off the thread.

Given that, I think Ink/Stitch is the place to handle the tie-offs (and tie-ins which use a similar algorithm), since it already has an algorithm for running stitch along a path.

tatarize commented 6 years ago

You wouldn't have to use these functions. And could be made to simply send STOP, COLOR_CHANGE, JUMP, and STITCH commands directly, and should. But, it should also have higher level stuff like, BREAK or BREAK_COLOR which means generally trim this stitch, and jump to the location of the next stitch.

If there would be a need to do the lower level stuff, you could compose those yourself. But, the embroidery machines only can do so many things. They do stitch, move x y, turn on the sequin adaptor, stop, color_change, and fire laser, (the last one's not entirely a joke, some machines do laser cutting of applique).

Anything you can do is broken into those parts. So you need have access to that stuff, and if you aren't doing anything novel being able to simply send it bunch of stitches and a couple of commands like, we are now changing colors and going somewhere else, seems pretty reasonable. Especially with the lower level ones.

tatarize commented 6 years ago

The tie-off and tie-on in pyembroidery, checks the previous stitch making sure it doesn't exceed the max-length allowed by the format, and stitches 33%, 66%, 33%, and within that last or first stitch.

tatarize commented 6 years ago

It lays out 4 stitches hidden within the last stitch. But, only if requested. You could do whatever else you want and not invoke the feature in the encoder. It would then just stitch them as you requested them. But, if somebody who isn't you is doing something else, they might well want to add those tie-on and tie-off stitches and could request it. But, if you'd rather do that yourself it's entirely reasonable for you to do that. They are features not requirements.

tatarize commented 6 years ago

At the low level, pyembroidery needs to do the same stuff libembroidery does. Take a bunch of raw stitches and commit them to the binary formats whether they make any sense or not. But, at the higher level it needs to take in the stuff that people actually do and use and render them into something that absolutely will make sense to the binary format.

While you've already written some of that for inkstitch, other people might not. So it will need stuff like tie-down, or frame ejects, or the ability to feed it large blocks of points, and write that to disk. As well as loading a bunch of binary commands and turning that into large blocks of points, some elements of metadata, and thread objects.

tatarize commented 6 years ago

I'm not trying to limit your ability to write in new features. I am wildly aware of the things embroidery machines can do and obviously giving you fine grain control is needed, but a lot of the time, it's just stitches to canvas. It stitches, that's basically all it does. Clearly it might need some other commands like slow or fast (ww mentions these exist in U?? format) that slow down the machine or speed them up at a specific point.

It's giving just shorthand for how the work actually gets done, on top of writing the direct binary commands. The shorthand however needs to include some kind of high level stuff but you could implement that yourself. There's really just not that much stuff embroidery machines can do. At a certain point you need something that works but that doesn't require you actually need to write every trim and jump command yourself.

You were stitching over there, in that thread. Now you moved over here with a new thread. I can figure out which commands you need to be written. I'll give you the power to write those yourself. For example, if you wanted an embroidery machine to trim, then jump around randomly for half an hour, that's entirely valid set of commands to write to binary. But, there'd be no shorthand for that.

tatarize commented 6 years ago

I updated the readme to better state the intentions here.

lexelby commented 6 years ago

Okay, great! Sounds like we're on the same page, then. I just wanted to make sure that the lower-level capabilities would be exposed. You're right that I may at some point want to use the higher-level stuff too in some cases.

tatarize commented 6 years ago

Also, anything that required such fine grain control to perform some action, could also be built into pyembroidery as a middle-level capability, as I cannot imagine any such thing wouldn't also be useful in a more general sense (Eg. *1) or that there's that much reason to warrant concern, embroidery machines have so few commands that "stitching these points here in this color" covers 99.9% of everything.

However, waiting for me to do such things would be a non-starter given your general pace at current. I'd be quite willing to give you commit access over the code as needed. The mandate for this project is generally limited by design. I might wrap up in a couple days or so, I think I'm down to the VP3 writer has some bug, EXP has an unknown conceptual flaw, hashing out the API, and making the encoder way more automatic between different format writes. Then it's just documenting things, and putting the library in useful places.

But, it would let you, going forward, just edit pyembroidery if you actually did find such a fine grain use case. I've been programming embroidery stuff for a decade and I cannot actually think of some reason you should want to put your color-changes, trims, stops, and jumps in some particular order that doesn't have everything to do with the exact format you are writing, and, thus, better located here.

I have a pretty extensive embroidery app with lots of interesting bells and whistles and even more proposed ideas and concepts. I cannot at all think of a reason you'd want to touch the stuff at that lowest level. I've never thought of a usecase (outside of moving the head around in circles forever), but it's like a line of code to pass through the lower level commands during encoding.

1

If for some proper established reasons your tie_on and tie_off procedures are better than mine. They could also be offered here, in addition to my chosen method. Though really, those tie-downs should be added to the stitch blocks so they can be toggled on and off at a per object level and not done during the writing, sort of like the check-boxes for stop-after and trim-after ... Actually this gives me a great idea for how to do the encoder and apis (namely have the various toggleable features encoded in commands TOGGLE_TIE_ON(0,0) MAX_STITCH_LENGTH(127, 127), TRANSLATE(x, y) SCALE(1.3, 1.3), then you could have these properties change on the fly and apply to the remaining stitches and never have to see the encoder, and the low level commands would pass through).

lexelby commented 6 years ago

Commit access would be excellent! It's kind of you to offer.

I'm impressed with how fast this is all coming together. Thank you for all of your work! Once you're feeling that things are stabilized, I'll start working on integrating it with Ink/Stitch.

I love that this thing is becoming more than a low-level layer for Ink/Stitch. Hopefully more Python embroidery projects pop up as a result.

In light of that, do you want to move this repo into the inkstitch github organization, or would you rather keep it separate? Either is fine with me. If it were in the github org, you'd still be the owner, if I understand these things correctly.

tatarize commented 6 years ago

Yeah, adding it to that organization would make more sense than creating my own. I'll send out the transfer, even if things go awry I still have all the code, even if I oddly finished it with a pull request I see no issue.

tatarize commented 6 years ago

"You don’t have the permission to create repositories on inkstitch"

tatarize commented 6 years ago

@lexelby It failed to transfer due to permissions. I can't make repositories in that organization. I guess I could send it to you and have you put it on the organization, or whatnot.

It's mostly done. Needs some feedback on properly utilizing the API stuff. But, doing more work there should be in response to need rather than guessing.

There's a few other small defects in some of the readers and writers that I'll get to, but like adding in additional readers and writers, they'd be nice to have, but it's reasonably decoupled from the rest of the code.

lexelby commented 6 years ago

Yup, I saw. Been a bit busy but I'll try to add you to the organization today.