# Setting restrict_to_unvisited=false isn't working as I expected in freestyle.types.Operators.chain

I'm trying to write a chaining iterator for Freestyle to produce a single, fully-joined chain; mathematically, I believe this requires me to trace each line twice.

I have written a simple chaining iterator, inheriting from ChainingIterator, with a traverse function which keeps track of visited edges and allows each to be visited exactly twice. The problem is that when I use it with the built-in chain operator, I'm not seeing edges that have been visited at all. According to the docs, I should be able to ask for all edges, including the visited ones, by setting restrict_to_unvisited=False in my iterator; indeed, this works fine when I use the bidirectional_chain operator instead of chain but uh, this also has the effect of resulting in a bidirectional chain (with the result that I'll end up with some segments visited thrice and some not at all, which is not what I'm looking for aesthetically for this project).

I have the following code:

from freestyle.predicates import (
QuantitativeInvisibilityUP1D,
FalseUP1D,
TrueUP1D
)
)
from freestyle.types import Operators

from freestyle.types import (
ChainingIterator
)

class singleLineIterator(ChainingIterator):
def __init__(self):
ChainingIterator.__init__(self, restrict_to_selection=True, restrict_to_unvisited=False, begin=None, orientation=True)
self.edgeDict = dict()

def init(self):
pass

def traverse(self, iter):
bestScore = 100
bestEdge = None
# "ve" means "view edge" apparently!
for ve in it:
score = self.edgeDict.get((ve.id.first, ve.id.second), 0)
if (score < bestScore):
bestEdge = ve
bestScore = score
print(bestScore) # this should be printing numbers higher than 0!
if bestEdge is None or bestScore >= 2:
return None
self.edgeDict[(bestEdge.id.first, bestEdge.id.second)] = bestScore+1
return bestEdge

Operators.select(QuantitativeInvisibilityUP1D(0))

Operators.chain(singleLineIterator(), FalseUP1D())
# Operators.bidirectional_chain(singleLineIterator(), FalseUP1D())

]


(Setup: basic cube, rotated slightly so the occluded edge isn't lining up with the front edge, for readability; Cycles renderer; Freestyle enabled, set to Python Scripting Mode, and using the above code as the only style module. Here's a .blend file with all this.)

Running the above code, the printout from line 45 never prints a number higher than 0. If I comment out line 54 and comment in line 55 (using bidirectional_chain instead of chain), I correctly see printed numbers up to and including 2.

In the linked .blend, I also have an svg_export.py with the same iterator, since it's easier to see the path continuity in an svg path. I marked the beginnings and endings of lines with a circle and a triangle, respectively:

So, how do I fix this? I think this means either:

1. actually convincing chain to give me previously-visited edges, or
2. hacking bidirectional_chain to be less bidirectional, which seems less elegant but maybe more doable.

P.S. Interestingly, restrict_to_selection is also not working as I expected when using chain: if restricted_to_unvisited=true, then both restrict_to_selection=true and restrict_to_selection=false have results that are restricted to the selection (i.e. not showing the occluded edge). restrict_to_selection=false only works as expected if restricted_to_unvisited is also false. This doesn't bother me as much for this project, but perhaps it's a clue as to what is going wrong?

P.P.S. Is there a way to use the built-in Freestyle SVG Exporter Add-on with my own Python Style Module here? It didn't seem to work (no svg export iff Freestyle was in Python Scripting Mode); it seemed easier to grab the code from github and integrate it than to actually debug it, but I'm idly curious.