Proposal to change the condition from axis.tag" to axis.name: conditions, locations use the axis.name.
This makes it possible to evaluate a rule without having to look up the axis data. Evaluate and apply a rule to a list of glyphnames. More tests.
This commit is contained in:
parent
c17592984f
commit
ab450a9017
@ -93,9 +93,11 @@ class RuleDescriptor(SimpleDescriptor):
|
||||
</rules>
|
||||
|
||||
Discussion:
|
||||
use axis names rather than tags - then we can evaluate the rule without having to look up the axes.
|
||||
remove the subs from the rule.
|
||||
remove 'enabled' attr form rule
|
||||
|
||||
|
||||
"""
|
||||
_attrs = ['name', 'conditions', 'subs'] # what do we need here
|
||||
def __init__(self):
|
||||
@ -103,6 +105,41 @@ class RuleDescriptor(SimpleDescriptor):
|
||||
self.conditions = [] # list of dict(tag='aaaa', minimum=0, maximum=1000)
|
||||
self.subs = [] # list of substitutions stored as tuples of glyphnames ("a", "a.alt")
|
||||
|
||||
def evaluateRule(rule, location):
|
||||
""" Test if rule is True at location """
|
||||
for cd in rule.conditions:
|
||||
if not cd['name'] in location:
|
||||
#print("skipping", cd['name'])
|
||||
continue
|
||||
#print(cd['minimum'] <= location[cd['name']] <= cd['maximum'])
|
||||
if not cd['minimum'] <= location[cd['name']] <= cd['maximum']:
|
||||
return False
|
||||
return True
|
||||
|
||||
def applyRules(rules, location, glyphNames):
|
||||
""" Apply these rules at this location to these glyphnames.minimum
|
||||
- rule order matters
|
||||
"""
|
||||
newNames = []
|
||||
for rule in rules:
|
||||
if evaluateRule(rule, location):
|
||||
for name in glyphNames:
|
||||
swap = False
|
||||
for a, b in rule.subs:
|
||||
if name == a:
|
||||
swap = True
|
||||
break
|
||||
if swap:
|
||||
newNames.append(b)
|
||||
else:
|
||||
newNames.append(name)
|
||||
glyphNames = newNames
|
||||
newNames = []
|
||||
return glyphNames
|
||||
|
||||
|
||||
|
||||
|
||||
class InstanceDescriptor(SimpleDescriptor):
|
||||
"""Simple container for data related to the instance"""
|
||||
flavor = "instance"
|
||||
@ -144,6 +181,7 @@ def tagForAxisName(name):
|
||||
tag = name[:4]
|
||||
return tag, dict(en = name)
|
||||
|
||||
|
||||
class AxisDescriptor(SimpleDescriptor):
|
||||
"""Simple container for the axis data"""
|
||||
flavor = "axis"
|
||||
@ -270,7 +308,7 @@ class BaseDocWriter(object):
|
||||
ruleElement.attrib['name'] = ruleObject.name
|
||||
for cond in ruleObject.conditions:
|
||||
conditionElement = ET.Element('condition')
|
||||
conditionElement.attrib['tag'] = cond.get('tag')
|
||||
conditionElement.attrib['name'] = cond.get('name')
|
||||
conditionElement.attrib['minimum'] = self.intOrFloat(cond.get('minimum'))
|
||||
conditionElement.attrib['maximum'] = self.intOrFloat(cond.get('maximum'))
|
||||
ruleElement.append(conditionElement)
|
||||
@ -460,7 +498,7 @@ class BaseDocReader(object):
|
||||
cd = {}
|
||||
cd['minimum'] = float(conditionElement.attrib.get("minimum"))
|
||||
cd['maximum'] = float(conditionElement.attrib.get("maximum"))
|
||||
cd['tag'] = conditionElement.attrib.get("tag")
|
||||
cd['name'] = conditionElement.attrib.get("name")
|
||||
ruleObject.conditions.append(cd)
|
||||
for subElement in ruleElement.findall('.sub'):
|
||||
a = subElement.attrib['name']
|
||||
@ -941,9 +979,9 @@ class DesignSpaceDocument(object):
|
||||
for rule in self.rules:
|
||||
newConditions = []
|
||||
for cond in rule.conditions:
|
||||
minimum = self.normalizeLocation({cond['tag']:cond['minimum']}).get(cond['tag'])
|
||||
maximum = self.normalizeLocation({cond['tag']:cond['maximum']}).get(cond['tag'])
|
||||
newConditions.append(dict(tag=cond['tag'], minimum=minimum, maximum=maximum))
|
||||
minimum = self.normalizeLocation({cond['name']:cond['minimum']}).get(cond['name'])
|
||||
maximum = self.normalizeLocation({cond['name']:cond['maximum']}).get(cond['name'])
|
||||
newConditions.append(dict(name=cond['name'], minimum=minimum, maximum=maximum))
|
||||
rule.conditions = newConditions
|
||||
|
||||
|
||||
@ -1071,8 +1109,8 @@ if __name__ == "__main__":
|
||||
>>> # write some rules
|
||||
>>> r1 = RuleDescriptor()
|
||||
>>> r1.name = "named.rule.1"
|
||||
>>> r1.conditions.append(dict(tag='aaaa', minimum=0, maximum=1))
|
||||
>>> r1.conditions.append(dict(tag='bbbb', minimum=2, maximum=3))
|
||||
>>> r1.conditions.append(dict(name='aaaa', minimum=0, maximum=1))
|
||||
>>> r1.conditions.append(dict(name='bbbb', minimum=2, maximum=3))
|
||||
>>> r1.subs.append(("a", "a.alt"))
|
||||
>>> doc.addRule(r1)
|
||||
>>> # write the document
|
||||
@ -1354,13 +1392,33 @@ if __name__ == "__main__":
|
||||
>>> # write some axes
|
||||
>>> r1 = RuleDescriptor()
|
||||
>>> r1.name = "named.rule.1"
|
||||
>>> r1.conditions.append(dict(tag='aaaa', minimum=0, maximum=1000))
|
||||
>>> r1.conditions.append(dict(tag='bbbb', minimum=0, maximum=3000))
|
||||
>>> r1.conditions.append(dict(name='aaaa', minimum=0, maximum=1000))
|
||||
>>> r1.conditions.append(dict(name='bbbb', minimum=0, maximum=3000))
|
||||
>>> r1.subs.append(("a", "a.alt"))
|
||||
>>>
|
||||
>>> doc.addRule(r1)
|
||||
>>> assert len(doc.rules) == 1
|
||||
>>> assert len(doc.rules[0].conditions) == 2
|
||||
>>> evaluateRule(r1, dict(aaaa = 500, bbbb = 0))
|
||||
True
|
||||
>>> evaluateRule(r1, dict(aaaa = 0, bbbb = 0))
|
||||
True
|
||||
>>> evaluateRule(r1, dict(aaaa = 1000, bbbb = 0))
|
||||
True
|
||||
>>> evaluateRule(r1, dict(aaaa = 1000, bbbb = -100))
|
||||
False
|
||||
>>> evaluateRule(r1, dict(aaaa = 1000.0001, bbbb = 0))
|
||||
False
|
||||
>>> evaluateRule(r1, dict(aaaa = -0.0001, bbbb = 0))
|
||||
False
|
||||
>>> evaluateRule(r1, dict(aaaa = -100, bbbb = 0))
|
||||
False
|
||||
>>> applyRules([r1], dict(aaaa = 500), ["a", "b", "c"])
|
||||
['a.alt', 'b', 'c']
|
||||
>>> applyRules([r1], dict(aaaa = 500), ["a.alt", "b", "c"])
|
||||
['a.alt', 'b', 'c']
|
||||
>>> applyRules([r1], dict(aaaa = 2000), ["a", "b", "c"])
|
||||
['a', 'b', 'c']
|
||||
|
||||
>>> a1 = AxisDescriptor()
|
||||
>>> a1.minimum = 0
|
||||
@ -1378,7 +1436,7 @@ if __name__ == "__main__":
|
||||
>>> doc.addAxis(b1)
|
||||
|
||||
>>> doc.rules[0].conditions
|
||||
[{'minimum': 0, 'tag': 'aaaa', 'maximum': 1000}, {'minimum': 0, 'tag': 'bbbb', 'maximum': 3000}]
|
||||
[{'minimum': 0, 'maximum': 1000, 'name': 'aaaa'}, {'minimum': 0, 'maximum': 3000, 'name': 'bbbb'}]
|
||||
|
||||
>>> doc.rules[0].subs
|
||||
[('a', 'a.alt')]
|
||||
@ -1387,7 +1445,7 @@ if __name__ == "__main__":
|
||||
>>> doc.rules[0].name
|
||||
'named.rule.1'
|
||||
>>> doc.rules[0].conditions
|
||||
[{'minimum': 0.0, 'tag': 'aaaa', 'maximum': 1.0}, {'minimum': 0.0, 'tag': 'bbbb', 'maximum': 1.0}]
|
||||
[{'minimum': 0.0, 'maximum': 1.0, 'name': 'aaaa'}, {'minimum': 0.0, 'maximum': 1.0, 'name': 'bbbb'}]
|
||||
|
||||
>>> doc.write(testDocPath)
|
||||
>>> new = DesignSpaceDocument()
|
||||
@ -1398,6 +1456,7 @@ if __name__ == "__main__":
|
||||
>>> len(new.rules)
|
||||
1
|
||||
>>> new.write(testDocPath2)
|
||||
|
||||
"""
|
||||
|
||||
p = "testCheck.designspace"
|
||||
|
@ -6,8 +6,8 @@
|
||||
</axes>
|
||||
<rules>
|
||||
<rule name="named.rule.1">
|
||||
<condition maximum="1" minimum="0" tag="aaaa" />
|
||||
<condition maximum="1" minimum="0" tag="bbbb" />
|
||||
<condition maximum="1" minimum="0" name="aaaa" />
|
||||
<condition maximum="1" minimum="0" name="bbbb" />
|
||||
<sub name="a" with="a.alt" />
|
||||
</rule>
|
||||
</rules>
|
||||
|
@ -6,8 +6,8 @@
|
||||
</axes>
|
||||
<rules>
|
||||
<rule name="named.rule.1">
|
||||
<condition maximum="1" minimum="0" tag="aaaa" />
|
||||
<condition maximum="1" minimum="0" tag="bbbb" />
|
||||
<condition maximum="1" minimum="0" name="aaaa" />
|
||||
<condition maximum="1" minimum="0" name="bbbb" />
|
||||
<sub name="a" with="a.alt" />
|
||||
</rule>
|
||||
</rules>
|
||||
|
13
README.md
13
README.md
@ -108,7 +108,7 @@ i2.glyphs['arrow'] = glyphData
|
||||
i2.glyphs['arrow2'] = dict(mute=False)
|
||||
doc.addInstance(i2)
|
||||
```
|
||||
# `Axis` descriptor object
|
||||
# `axis` descriptor object
|
||||
* `tag`: string. Four letter tag for this axis. Some might be registered at the OpenType specification.
|
||||
* `name`: string. Name of the axis as it is used in the location dicts. MutatorMath + Varlib.
|
||||
* `labelNames`: dict. When defining a non-registered axis, it will be necessary to define user-facing readable names for the axis. Keyed by xml:lang code. Varlib.
|
||||
@ -130,13 +130,14 @@ a1.map = [(0.0, 10.0), (401.0, 66.0), (1000.0, 990.0)]
|
||||
```
|
||||
# `rule` descriptor object
|
||||
* `name`: string. Unique name for this rule. Will be used to reference this rule data.
|
||||
* `conditions`: list of dicts with condition data. `
|
||||
* `conditions`: list of dicts with condition data.
|
||||
* Each condition specifies the axis name it is active on and the values between which the condition is true.
|
||||
|
||||
```python
|
||||
r1 = RuleDescriptor()
|
||||
r1.name = "unique.rule.name"
|
||||
r1.conditions.append(dict(tag="aaaa", minimum=-10, maximum=10))
|
||||
r1.conditions.append(dict(tag="bbbb", minimum=-10, maximum=10))
|
||||
r1.conditions.append(dict(name="aaaa", minimum=-10, maximum=10))
|
||||
r1.conditions.append(dict(name="bbbb", minimum=-10, maximum=10))
|
||||
```
|
||||
|
||||
# Subclassing descriptors
|
||||
@ -415,14 +416,14 @@ myDoc = DesignSpaceDocument(KeyedDocReader, KeyedDocWriter)
|
||||
* Between the `minimum` and `maximum` this rule is `true`.
|
||||
|
||||
### Attributes
|
||||
* `tag`: string, required. Must match one of the defined `axis` tag attributes.
|
||||
* `name`: string, required. Must match one of the defined `axis` name attributes.
|
||||
* `minimum`: number, required. The low value.
|
||||
* `maximum`: number, required. The high value.
|
||||
|
||||
# 5.1.2 `sub` element
|
||||
* Child element of `rule`.
|
||||
* Defines which glyphs to replace when the rule is true.
|
||||
* This element is optional.
|
||||
* This element is optional. It may be useful for editors to know which glyphs can be used to preview the axis.
|
||||
|
||||
### Attributes
|
||||
* `name`: string, required. The name of the glyph this rule looks for.
|
||||
|
Loading…
x
Reference in New Issue
Block a user