feature suggestion

Let the developers know what you think of the software and what can be done to either improve the CFDG language or the Context Free program.

Moderators: MtnViewJohn, chris, mtnviewmark

Post Reply
logic
Posts: 8
Joined: Thu Apr 13, 2006 11:16 am

feature suggestion

Post by logic »

I originally posted this to the old boards, which I reached through Help->Forums + FAQ in the Context Free application. I'm reposting it here since these boards seem to be more active.
___________________________________________________

There is a large class of fractals that Context Free is currently unable to do because there is no way to update a rule's transformation matrix from within the rule. My proposition is for transformations in angle brackets (< >) to be processed like transformations in square brackets ([ ]) but actually update the parent's transformation matrix, instead of restoring it after running the rule. The transform should also be updatable without invoking another rule. For instance, the following should all be equivalent:

Code: Select all

# The old way:
rule OUTLINESQUARE_OLD
{
  SQUARE [ y 5 s 1 10 ]
  SQUARE [ y 10 r 90 y 5 s 1 10 ]
  SQUARE [ y 10 r 90 y 10 r 90 y 5 s 1 10 ]
  SQUARE [ y 10 r 90 y 10 r 90 y 10 r 90 y 5 s 1 10]
}

# The new way, style 1:
rule OUTLINESQUARE
{
  <y 5>
  SQUARE { s 1 10 }
  <y 5 r 90 y 5>
  SQUARE { s 1 10 }
  <y 5 r 90 y 5>
  SQUARE { s 1 10 }
  <y 5 r 90 y 5>
  SQUARE { s 1 10 }
  <y 5 r 90>
}

# The new way, style 2:
rule OUTLINESQUARE2
{
  SQUARE < y 5 s 1 10 >
  SQUARE < s 1 .1 y 5 r 90 y 5 s 1 10 >
  SQUARE < s 1 .1 y 5 r 90 y 5 s 1 10 >
  SQUARE < s 1 .1 y 5 r 90 y 5 s 1 10 >
  < s 1 .1 y 5 r 90 >
}

# The new way, style 3:
rule OUTLINESQUARE3
{
  <y 5>
  SQUARE { s 1 10 }
  CORNER < >
  SQUARE { s 1 10 }
  CORNER < >
  SQUARE { s 1 10 }
  CORNER < >
  SQUARE { s 1 10 }
  <y 5 r 90>
}
rule CORNER
{
  <y 5 r 90 y 5>
}
Note that these 3 examples all explicitly restore the transformation matrix before finishing.

Of course, rules would have to be careful if there were any possibility they were going to be invoked in this way, but any failure (or intentional choice not) to restore the transform to the initial state would be the caller's problem, since invoking such a rule with { } wouldn't propagate the changes to the caller.

A rule's <> behaviour can also be masked, so that even if it is called with <>, no change is made to the caller's matrix:

Code: Select all

rule PROXY
{
  INNERRULE {}
}

rule INNERRULE
{
  <whatever>
  OTHERRULE <whatever>
}
By making PROXY the external entry-point into the rule, it would appear that the rule restored its matrix even when it did not.

Adding this rule will allow for some L-systems to be written in CFDG, and the suggestion I've seen in another thread for a counter parameter to allow selection of rules based on recursion depth (or the suggestion I made after originally posting this to add parameters to rules) will complete the support. :-)
_____________________________________________________

After thinking through it, this also doesn't seem to break the context free paradigm. Rules will still behave exactly the same way, conforming to the transformation they are given. This syntax is essentially a shorthand for embedding the transformations directly into the transformation lists for the other rules invoked as part of a rule. The fact that my example above can be represented without the new syntax (at the expense of readibility/conciseness) is evidence of this.

This change would also add a degree of reusability/hiding of implementation, in that, for instance, a rule wouldn't need to know the particulars of a font ruleset that it imported in order to use it and place glyphs correctly:

Code: Select all

# Old way:
rule HELLO
{
  H_5by5 { x 0.0 }
  E_5by5 { x 1.2 }
  L_5by5 { x 2.4 }
  L_5by5 { x 3.6 }
  O_5by5 { x 4.8 }
}

# New way:
rule HELLO2
{
  H_5by5 <>
  E_5by5 <>
  L_5by5 <>
  L_5by5 <>
  O_5by5 <>
}
Any comments?

User avatar
MtnViewJohn
Site Admin
Posts: 882
Joined: Fri May 06, 2005 2:26 pm
Location: Mountain View, California
Contact:

Post by MtnViewJohn »

So let me understand this:
  1. Geometry and/or color adjustments in angle brackets modify the shape's geometry and/or color for all subsequent shape replacements.
  2. Shape rules are able to "return" the sum of these in-shape adjustments to the calling shape rule.
  3. If you use angle brackets in a shape replacement then the returned color/geometry adjustment modifies the shape color/geometry as in #1 above
#1 is easy to implement and doesn't violate the context-free property of cfdg files. But #2 and #3 are both impossible and violate the CF property. In your last example H_5by5 <> has an effect on the appearance of E_5by5 <> and all the others. According to the CF property a shape's appearance is only affected by its ancestors, not by its siblings, cousins, etc.

The reason that it is impossible is because of the lazy execution model of Context Free. When a shape rule is executed the SQUAREs, CIRCLEs, and TRIANGLEs are drawn right away but the non-primitive shapes are tossed into a complex data structure and run at an indeterminate time later. So the returned geometry/color won't be known until long after the calling shape rule has completed. The only way it could be made to work is to only return the sum of the <color/geometry adjustments> that are in the shape rule and not include the adjustments that are from child shapes. That's because this info is known at parse time so the renderer can access it.

But even if we simplified the feature so that it could be implemented it would still violate the CF property. I think that this kind of thing works for L-systems because they execute child shape right away. We can't do that in Context Free because it is too easy to get into infinite loops. Recursive CFDG grammars recurse infinitely, there is no syntax for ending the recursion. What does break the infinite recursion is the stopping rule that cancels shape execution for shapes that are less than 0.3 pixels. This kind of recursion stopping is very brittle if child shapes are executed immediately but not if they are executed in a lazy manner, with the largest shapes executed first.

logic
Posts: 8
Joined: Thu Apr 13, 2006 11:16 am

Post by logic »

MtnViewJohn wrote:[snip]
I think that this kind of thing works for L-systems because they execute child shape right away.
This isn't quite how it works. The reason L-systems can do things that Context Free can't is that they:
  1. impose a specific order onto the shapes being drawn, and
  2. consider a change in the transformation matrix to be a fundamental part of the primitive drawing operations.
The way these are put together is to consider the entire drawing to be one long string of sequential drawing operations; the hierarchy disappears as part of the (pre-?)render process. Once the requested number of levels of recursion have been generated (this is done before anything is actually drawn), the interpreter maintains a current (x, y), angle and size. Each command in the sequence optionally draws a line starting at the current position with the current size, and optionally updates the current state.

As a simple example, consider the Koch coastline:

F=F+F-F+F

..where +/- adjust the angle without adjusting the position or drawing anything, and F draws a line 1 unit long at the current angle starting at the current (x, y).

With only one level of recursion, this gives the well-known line with a bump in it:

__/\__

The renderer draws this given the string "F+F-F+F". After a second level of recursion, the much longer (and increasingly hard to read) string: "F+F-F+F+F+F-F+F-F+F-F+F+F+F-F+F" draws the next level, with a bump on each of the lines in the first diagram.

So, before I get into a huge rant on this, I'll just summarize it: I now have a better understanding of the CF property and what it means in terms of restricting the flow of information. L-systems are, then, basically the exact opposite of Context Free. Starting with similar languages for describing the drawing, L-systems flatten the hierarchy first, and then draw with, well, a context :-) being updated by each primitive command. Context Free, on the other hand, keeps the hierarchy and actually uses it as the fundamental mechanism for conveying state information to be used when drawing shapes. Because of this mechanism, it can make assumptions that I'd think would greatly simplify the rendering engine.

I guess they're just fundamentally incompatible. :wink:

Post Reply