diff --git a/rocolib/api/Parameterized.py b/rocolib/api/Parameterized.py index 1fc3fbcb7646c6d3d708abbbde25c0fedb68f65b..b3d3632d80beb0f416c2b62e9697b9be63b9cd30 100644 --- a/rocolib/api/Parameterized.py +++ b/rocolib/api/Parameterized.py @@ -44,8 +44,8 @@ class Parameter: self.name = name - if defaultValue is None and not kwargs.get("optional", False): - raise ValueError(f"Must specify either defaultValue or optional=True for parameter {name}") + if defaultValue is None and not kwargs.get("overrides", False): + raise ValueError(f"Must specify either defaultValue or overrides (implies optional) for parameter {name}") self.defaultValue = defaultValue self.spec = {} @@ -60,7 +60,7 @@ class Parameter: self.assertValid(defaultValue) vt = self.spec.get("valueType", "") - no = not(self.spec.get("optional", False)) + no = not(self.spec.get("overrides", False)) if no and ("int" in vt or "float" in vt): integer=None @@ -94,11 +94,11 @@ class Parameter: def assertValid(self, value): if value is None: - if self.spec.get("optional", False): + if self.spec.get("overrides", False): self.value = value return else: - raise ValueError(f"Parameter {self.name} is not optional and cannot be set to None") + raise ValueError(f"Parameter {self.name} is not optional (via overrides) and cannot be set to None") def check(spec, test, error): if (self.spec.get(spec, None) is not None and not test(self.spec[spec])): @@ -116,6 +116,32 @@ class Parameter: else: return self.symbol + def doOverrides(self, c): + if self.value is None: + return + overrides = self.spec.get("overrides", []) + if isinstance(overrides, dict): + for k, fn in overrides.items(): + try: + import rocolib.utils.numsym as np + value = eval(fn, locals()) + c.setParameter(k, value) + except ValueError as e: + raise ValueError(str(e) + f" (via setting overriding parameter {self.name} to {self.value})") + except KeyError as e: + logging.debug(str(e) + f" (via setting overriding parameter {self.name} to {self.value}) -- ignoring") + elif isinstance(overrides, (list, tuple)): + for k in overrides: + try: + c.setParameter(k, self.value) + except KeyError as e: + logging.debug(str(e) + f" (via setting overriding parameter {self.name} to {self.value}) -- ignoring") + else: + try: + c.setParameter(overrides, self.value) + except KeyError as e: + logging.debug(str(e) + f" (via setting overriding parameter {self.name} to {self.value}) -- ignoring") + def getInfo(self, keys=None): if isinstance(keys, str): return getattr(self, keys) @@ -158,6 +184,8 @@ class Parameterized(object): """ for n, p in self.parameters.items(): p.setDefault(force) + for n, p in self.parameters.items(): + p.doOverrides(self) def setParameter(self, n, v, validate=True): diff --git a/rocolib/builders/ServoMountBuilder.py b/rocolib/builders/ServoMountBuilder.py index 53ba903b7cc5da142c3b960a361356d39d971f91..900cde2bee26aaca5763731e18ebf5de336e79c1 100644 --- a/rocolib/builders/ServoMountBuilder.py +++ b/rocolib/builders/ServoMountBuilder.py @@ -4,11 +4,13 @@ from rocolib.api.Function import Function c = Component() c.addParameter("servo", "fs90r", paramType="dimension") + c.addParameter("flip", False, valueType="bool") c.addParameter("center", True, valueType="bool") c.addParameter("shift", 0, paramType="length") + # XXX TODO: Define type: tuple of two numbers -c.addParameter("offset", optional=True, overrides=("flip", "center", "shift")) +c.addParameter("offset", 0) c.addSubcomponent("beam", "SimpleRectBeam", inherit=("length", "addTabs"), prefix=None) c.addSubcomponent("mount", "Cutout") diff --git a/rocolib/library/Cutout.py b/rocolib/library/Cutout.py index 77cb2bb855a3b682dadb19ff619373c8e67a60b9..feb51f78d409d19cf57763e17717436a0a12d479 100644 --- a/rocolib/library/Cutout.py +++ b/rocolib/library/Cutout.py @@ -2,20 +2,18 @@ from rocolib.api.components import DecorationComponent from rocolib.api.composables.graph.Face import Rectangle class Cutout(DecorationComponent): - def define(self): - self.addParameter("dx", 10, paramType="length") - self.addParameter("dy", 20, paramType="length") - self.addParameter("d", optional=True, overrides=("dx", "dy")) + def define(self): + self.addParameter("dx", 10, paramType="length") + self.addParameter("dy", 20, paramType="length") + self.addParameter("d", overrides={ + "dx": lambda c : c.getParameter("d"), + "dy": lambda c : c.getParameter("d"), + }) - def modifyParameters(self): - if self.getParameter("d") is not None: - self.setParameter("dx", self.getParameter("d")) - self.setParameter("dy", self.getParameter("d")) - - def assemble(self): - dx = self.getParameter("dx") - dy = self.getParameter("dy") - self.addFace(Rectangle("r0", dx, dy), prefix="r0") + def assemble(self): + dx = self.getParameter("dx") + dy = self.getParameter("dy") + self.addFace(Rectangle("r0", dx, dy), prefix="r0") if __name__ == "__main__": Cutout.test() diff --git a/rocolib/library/MountedServo.yaml b/rocolib/library/MountedServo.yaml index f6353e834719629510fc9f1d0a4b7d3a499e96ff..2bcbbe856c365fb6e99e765ce77c4e9eb30eb08d 100644 --- a/rocolib/library/MountedServo.yaml +++ b/rocolib/library/MountedServo.yaml @@ -133,13 +133,8 @@ parameters: units: mm valueType: (float, int) offset: - defaultValue: null - spec: - optional: true - overrides: - - flip - - center - - shift + defaultValue: 0 + spec: {} servo: defaultValue: fs90r spec: diff --git a/rocolib/library/RectBeam.py b/rocolib/library/RectBeam.py index 60abf3d0b1754f200d4ae23e525c5cd081695c84..12a323d930b73a635beb4066cf622199345bec8b 100644 --- a/rocolib/library/RectBeam.py +++ b/rocolib/library/RectBeam.py @@ -14,7 +14,7 @@ class RectBeam(FoldedComponent): self.addParameter("tangle", 80, paramType="angle", maxValue=180) self.addParameter("bangle", 135, paramType="angle", maxValue=180) - self.addParameter("root", optional=True, valueType="int") + self.addParameter("root", 0, valueType="int", minValue=0) self.addParameter("addTabs", True, valueType="bool") for i in range(4): diff --git a/rocolib/library/ServoMount.yaml b/rocolib/library/ServoMount.yaml index 829101ab4f87dd380d724ddf8cb1ca6efa48b2e4..9aa85d0a9c0343683df7bf9cd76862ac8c6781bf 100644 --- a/rocolib/library/ServoMount.yaml +++ b/rocolib/library/ServoMount.yaml @@ -73,13 +73,8 @@ parameters: units: mm valueType: (float, int) offset: - defaultValue: null - spec: - optional: true - overrides: - - flip - - center - - shift + defaultValue: 0 + spec: {} servo: defaultValue: fs90r spec: diff --git a/rocolib/library/Stool.py b/rocolib/library/Stool.py index 3bf5b6ed795df83b51f9658e7dff1d27e4a7d147..a7d4165d83199419a49f285b620fb337193dd2a6 100644 --- a/rocolib/library/Stool.py +++ b/rocolib/library/Stool.py @@ -8,14 +8,12 @@ class Stool(FoldedComponent): def define(self): self.addParameter("height", 60, paramType="length", minValue=10) self.addParameter("legs", 3, paramType="count", minValue=1) - self.addParameter("radius", optional=True, overrides=("legwidth",)) - self.addParameter("legwidth", 20, paramType="length", minValue=10) + self.addParameter("radius", minValue=10, overrides={ + "legwidth": lambda c: r2l.r2l(c.getParameter("radius"), c.getParameter("legs")*2) + }) + self.addParameter("legwidth", 20, paramType="length", minValue=9) self.addParameter("angle", 80, paramType="angle") - def modifyParameters(self): - if self.getParameter("radius") is not None: - self.setParameter("legwidth", r2l.r2l(self.getParameter("radius"), self.getParameter("legs")*2)) - def assemble(self): h = self.getParameter("height") lp = self.getParameter("legs") diff --git a/rocolib/library/UChannel.py b/rocolib/library/UChannel.py index 010014daf61e217b8a4fe479642f6c95091e4f8f..088b9acbf4c0694e6b1a95d4dbad2af19edf4a41 100644 --- a/rocolib/library/UChannel.py +++ b/rocolib/library/UChannel.py @@ -9,9 +9,12 @@ class UChannel(FoldedComponent): self.addParameter("depth", 20, paramType="length") # Minimum of 45deg to make sure the geometry stays convex - self.addParameter("angle", optional=True, overrides=("tangle", "bangle")) self.addParameter("tangle", 80, paramType="angle", minValue=45) self.addParameter("bangle", 135, paramType="angle", minValue=45) + self.addParameter("angle", paramType="angle", minValue=45, overrides={ + "bangle": lambda c : c.getParameter("angle"), + "tangle": lambda c : c.getParameter("angle"), + }) for i in range(3): self.addEdgeInterface("topedge%d" % i, "r%d.e0" % i, ["depth", "width"][i % 2]) @@ -23,11 +26,6 @@ class UChannel(FoldedComponent): self.addEdgeInterface("ledge", "r0.e3", "length") self.addEdgeInterface("redge", "r2.e1", "length") - def modifyParameters(self): - if self.getParameter("angle") is not None: - self.setParameter("bangle", self.getParameter("angle")) - self.setParameter("tangle", self.getParameter("angle")) - def assemble(self): bangle = 90 - self.getParameter("bangle") tangle = 90 - self.getParameter("tangle") diff --git a/rocolib/library/Wheel.yaml b/rocolib/library/Wheel.yaml index 7d22b01b470b52e2020ad78e7a78856e00e82eef..f902aa7f8e451b6254f78e167f1f747a333f9a4c 100644 --- a/rocolib/library/Wheel.yaml +++ b/rocolib/library/Wheel.yaml @@ -133,13 +133,8 @@ parameters: units: mm valueType: (float, int) offset: - defaultValue: null - spec: - optional: true - overrides: - - flip - - center - - shift + defaultValue: 0 + spec: {} radius: defaultValue: 25 spec: