When editing a pattern, I frequently run into the problem that an object, say a curve, can only access objects that are prior to it in the construction sequence. So if I need an additional point, e.g. as a reference to a handle, I have to use ‘History’ in order to have the new point inserted prior to the curve. I was wondering if this could not be relaxed. The only reason I can imagine why it is done in this way, is to avoid circularity: an object depending - indirectly - on itself. Obviously, that is not permissible. However, if after creating an object it would only be accepted after a circularity check, one could avoid such problems. Compare it to Excel. A cell can make use of all other cells, also the ones typed in later, as long as there is no circularity involved. When typing a formula in Excel that does show circularity, this is refused and one has to think a little harder to find a correct solution. With these checks, Excel sheets remain fully executable, while conserving the desirable characteristic that everything remains available independent of order of introduction. The program must already have procedures to test dependence. This is used to deny deletion of objects for instance. So it seems to me - but I do not know the code of course - that such a feature would not be very hard to implement. Stupid idea?
Yes it does.
Not so easy. Probably would take a total rewrite of the applications. Not to mention the performance hit the app would probably take.
Don’t know if you’re familar with using video and audio plugins in an editor, where some plugins use a “look ahead” method of analyzing the data, so as you’re editing (in real time?) future data is available… well that’s kinda of what we would probably have to do. That would probably entail double reparsing the whole pattern everytime anything is changed. Reparsing means every tool is created in order from beginning to end based on the formulas used, and there in lies the problem - the formulas.
Is it a stupid question… no. I also thought years ago well how hard can it be? … until I started to unravel the code and began to wrap my head around it.
That being said… my advice is to outline or plan out what you need to do in a pattern beforehand so as to (hopefully) avoid the lack of availability of future tools issue.
@Douglas, if I understand it well, the problem is in the order in which the objects are drawn. They follow the sequence of introduction, so point A78 is not known yet when you construct A38. You would have to draw A78 first, in a preliminary run, to then construct A38. That would require a lot of double work, indeed. However, why are objects drawn in the order of introduction? Suppose you asign a rank to every object. A would be rank 0. Points dependent on A would rank 1. An object depending on other ranks, say 3 and 7, would automatically get the rank (1+the highest underlying rank), 8 in this case. You could then reorder the functions to draw the points, and as long as there is no circularity, this would work - in my primitive ideas. There could be ties, but these should be no problem, as objects of the same rank cannot depend on each other. I guess a ranking is relatively easy to construct on the basis of dependence trees. An object’s rank can be calculated at the moment of creation. Not sure, though, if a rank could be changed due to changes in the pattern.
No, @peterh, nothing is stupid
Actually, it would be possible if the program was written in html5, because it reads the whole document into memory. however, the Seamly data document is written in xml, which, as I understand it, is more linea. The html5 is for creating websites, so it won’t work in software situations.
And, as far as Excel is concerned, yes, it will warn you when you create a circular formula, however, it doesn’t have nodes that are connected by lines and curves, it is only numbers in a cell that has a row & column reference. So, I guess, the answer to this being to avoid circularity is both yes & no.
One could better compare Seamly to Inkscape, Illustrator or Coreldraw, however, that wouldn’t be quite it, either because you can’t create formulas from those lines and nodes. Nor can you put in a measurements file to draw the different lines, etc. using those measurements over & over again. You can only use scripts or macros. You also don’t have as much control of the curve handles (or not that I know of) as you do in Seamly.
I used make the curves as I work, just to have something in place and then, when I have my basic pattern created, I delete them, create the extra lines that I will need to make my curves & redo them right at the end of the piece. But since then, I have mastered using the History and I absolutely love it, even if I get the odd crash from time to time.
Anyway, this is as I understand it, but I’m not a programmer. Perhaps @Douglas can explain it better than I can - having a better understanding than I.
How else would you parse the file?
The val xml is representative of the history ( or vice versa). It starts with draft block 1… creates the 1st point - lets assume basepoint A, creates the next tool…A1, etc etc. It’s like trees… were leaves don’t just grow in the middle of the air. We can’t just arbitrarily start creating a pattern in the middle somewhere… and again, it’s the formulas. A formula will usually reference another tool, and that tool’s class HAS TO exist. And conversely you can’t know about future tools, unless you parse 1st - so any formulas are adjusted, then you can parse again with the now known future tools. Take away the formulas and we don’t have this issue, but then we wouldn’t have a parametric pattern app either - we would just have your typical vector drawing app.
The xml IS read into memory when you load a pattern. It’s read into a QDomDocument. The QDomDocument is a class to handle reading and writing xml fikes. When you save a DomDoc it is written back to the (an) xml. A DomDoc does not have to be written linear… that’s not why val files are linear. In fact everytime you make a change to a tool - like changing it’s line color - you’re editing the DomDoc non linear.
The issue is not whether it’s in memory or not, it’s a matter of being able to (pre) parse the document. You have to be able to parse the whole document so you can (math) parse all the formulas… then you can go through again and create the tools to display on the screen. Currently we don’t always have to do a full parse… such as moving a point name. If we wanted to make all tools available to any other tool, we’d have to full parse with every change that affects formulas.
Exactly. It’s the parametric nature of the apps that make it what it is… otherwise like I said you’ve just got another vector app like Inkscape, Illustrator, or Coreldraw. It’s the formulas though that are imposing the linear nature of the app.
@Douglas and @Grace, I think I did not express myself sufficiently clear yesterday. The reason why I compare Seamly2D to spreadsheets is that both programs share a fundamental similarity, which is largely absent in graphical programs like inkscape etc. The similarity, at an abstract level, is the following. Both programs have objects (cells in a spreadsheet, points, lines etc. in Seamly) that depend on user input and/or features of other objects in the program. An object is a formal procedure, resulting in a tangible product (a number in a spreadsheet, a line or curve etc in Seamly), as a function of its input. Because the input can consist of other objects, this creates a tree of dependencies among the objects. In such a tree, an object can only be calculated and produced under the condition that all objects on which it depends are already known. The dependencies therefore create the problem of calculation order. You cannot calculate all cells in a spreadsheet in a random order, and neither can you do this with objects in Seamly. The way in which Seamly treats this calculation order problem, is by imposing chronological order. An object can only depend on the objects that were created prior to it. You can cheat a bit by playing with ‘History’, but that does not change the fundamental linear, chronological construction of the program. Spreadsheets could do that too. If the person creating the spreadsheet with all kinds of complex functions, were very orderly, she would introduce all cells in a strict order of dependency and everything would be calculated in chronological order and be fine. But then that person hands this spreadsheet to her boss, and the boss must show that she is on top of things by requiring some changes (I am speaking for myself here, as this is how I tend to treat my students ). We are entirely costumed to the fact that this is not a fundamental problem. We do not need to redo the entire spreadsheet, just add this additional parameter, change some formulae and check that the result now changes a loss in a profit. How come this is possible? This is because spreadsheets do not calculate cells in the order in which they were typed in, but based on dependencies. A nice forum post describing how this is done in LibreOffice Calc (older versions, I think it is more complicated now) is here: https://forum.openoffice.org/en/forum/viewtopic.php?t=103276. It describes the systems of ranks (called tiers here) that I intuitively suggested yesterday - I only discovered the forum today. You basically asign a tier to every cell, depending on the tiers of the cells it depends on. A cell always has a tier that is one unit higher than the highest tier of the objects it depends on. When recalculating, you first calculate the cells of the lowest tier, then the next one etc. - in this order you are sure that all information is available for the cell X you are calculating. The only thing you have to avoid is circularity, as this is incompatible with the tier system. Modern spreadsheets make it more complex to permit some temporary circularity, but I have no clear insight in how it works precisely and for this discussion it does not matter. Basically, therefore, spreadsheets allow editing of cells because they maintain a dependency tree that allows them to always update the position of a cell in the tier system after a change, and then are assured that every cell can always be calculated, while in the revision you can use almost all other cells (circularity excluded). If you would apply this to Seamly2D, changing an object X would involve the following steps (assuming that a dependency tree already exists, but I think this must be the case):
- Check all dependencies of the object X and identify all its descendants, i.e. all objects that depend directly or indirectly on X.
- Exclude all these descendants from the formula interface, comparable to how this interface is now restricted to objects that are prior in the chronological sequence. This way, circularity in formulae is avoided.
- Check if the points on which X depends are also not circular, i.e. not occurring in the dependency tree as descendants of X
- After accepting the modification of X, adjust the dependency tree to reflect the changes in object X. This may consist of cutting some links and adding some new ones
- Update the tier level of X. If after the change it depends on an object higher in tier than before the modification, its tier will have to go up.
- If the tier has gone up, check all descendants and update their tier also, where needed.
As you can see, this involves only relatively easy and fast database operations, but no repetitive constructions of graphical elements etc. I estimate it should not jeopardize the speed of the program too much. When saving the pattern, the tier information can easily be stored with all the objects, ensuring that the order of drawing the objects is conserved and the pattern appears fast after opening. Also, the stored tiers should be helpful in reconstructing the dependency tree, as this tree could be built up gradually while the objects are already being constructed. The stored calculation order would basically replace the chronological order, which should leave most of the program more or less like it is now.
But please do not misinterpret my suggestion. I am fully aware that this would involve some fundamental changes and is not the easiest operation to implement. Also, it is not urgent as the program now also works fine within some limitations. I only intended this as sketching a longer-term possibility worth looking at.
Yeah —it’s called the History list.
Hence why @Douglas believes it would involve basically a complete re-write of Seamly2D. It has been investigated before.
I hold out hope that once the insidious bugs & messy code get cleaned up an elegant & lite solution will become obvious. I remember that one of the times this issue came up a better method than previously considered did come to light, but that merely brought it down from “Google AI could do it,” to a PC compatible solution.
We are grateful for the input, & if you happen to know of a source of grant money which would be eager to enable someone to take on re-coding Seamly as their day-job, we beg you to please help make the connection!
Well after that long dissertation it’s obvious you have it all figured out… who knew Seamly2D is just a spreadsheet?
Good luck in rewriting your own fork to accomplish this.
So, yes. at the moment, @Douglas is busy ‘cleaning’ up the program and adding some very much needed features.
Thank you very much.
@Douglas, sorry for being carried away in my attempt to explain what I really meant. I had insufficiently realized that you must not be waiting for such wild and abstract ideas in a situation that is already quite stressed. Thanks @Pneumarian and @Grace for pointing this out. I regret having put this extra burden, especially since in this short time on the forum I have come to know you as an extremely dedicated developer. With this I hope we can close this topic and return to what really matters at this moment?
Sorry for my terse response, but as you might imagine it gets a bit tedious trying to explain to new users why it’s simply not possible (as structured) to allow for NLE of patterns.
Maybe this is the best response to the issue years ago by KMF…
"I would suggest that you pick a patternmaking system and learn it and make at least a few paper patterns. Once you have done this it should be more clear to you why it makes sense to use Valentina the way it is.
I understand your issue with a “forward reference” to a value to be defined in the future, but I believe that to have that issue means you are thinking like a programmer and that thinking like a patternmaker is different. Just my 2 cents".
As a trained draftsmen and pattern maker for 40+ years, I would tend to agree with these statements. Sometimes we just have to accept, and think “inside the box”.
Which, as a scientist for 40+ years, is not exactly what I have been trained in. Anyway, I happily return to my pleated trousers pattern.
Since I really have nothing to do at work today, I have the time to read / reread topics on the issue. I found this one by RT - the orginal dev:
“To avoid such a problem we could propose a “forward declaration” agreement. In your case, to get correct position you need recalculate pattern twice. First time you gather information and ignore missed parents data, next time you have all you need to correctly position pieces.”
Which is basically what I’ve said would need to be done. We’d have to parse the pattern twice… kinda of like compiling a program with forward declarations. - you won’t know what the reference value is until the future file is compiled. Again, my concern would be the efficiency hit the app would take having to parse twice.
And Susan’s response on the issue - along the same lines as KMF:
“Learning to make patterns is like learning to create mathematical proofs – you know where you need to go before you begin. Similar to proofs, when you make a mistake you must sometimes start over, but this will happen less and less as you build patternmaking skills, just like building math skills, and very much like learning how to apply engineering knowledge to create a CAD drawing - knowing the engineering is half the problem, understanding how the CAD program works is the other half. To sum up, all the information contained in a pattern is related, and order is important, so there will always be a temporal constraint.”
You are absolutely right in that. Forward projection is a can of worms. It would very easily lead to circularity too. That’s why I think the solution is in making the calculation order different from the chronological order, in such a way that you never have to do a forward projection but still can use ‘later’ objects as long as they are independent. It requires an efficient dependency tree, among other things, but it should never lead to the kind of problems you sketch.
My solution is to work on other features that will be far more useful to pattern making, rather than trying to eliminate a minor limitation of the apps, that can easily be overcome by planning a pattern out before hand.
Fair enough - I guess there is enough to do!
In the mean time, my-pattern.cloud is dependencies aware and if you have any refactoring of a pattern to do you could try it there. There is one caveat, Seamly2D sometimes requires a line to be defined in order to know its length, MyPattern can use the distance between any two points. I’ve not worked out what the logic is that drives the line to be required sometimes, and I don’t want to get into the code for IPR reasons.
I’m guessing, from the error messages you get when loading a corrupt file, that Seamly2D doesn’t parse formulas on load, but just evaluates them optimistically when the value is required. To get a full dependencies map you need to parse the formulas. I’m happy to share any coding or techniques should this rise to the top of the Seamly2D wish list.
Can’t login… I just get an error 500 code?
Of course Seamly2D parses the formulas when the pattern is loaded… how else would it create and refresh the geometries to draw each tool’s graphicItem?