From c99905e0075c94162a968c56b57d26fd7e3d60a4 Mon Sep 17 00:00:00 2001 From: David Osterberg Date: Sat, 13 Feb 2021 09:51:25 +0100 Subject: [PATCH] Draft: advanced indexing in Skip for Array syntax aligned with Part_CompoundFilter syntax. With the extension that index patterns can be intermixed with manual enumeration in a matlab style: [1, 3:6:2] -> [1. 3, 5] --- src/Mod/Draft/draftobjects/array.py | 75 ++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/src/Mod/Draft/draftobjects/array.py b/src/Mod/Draft/draftobjects/array.py index a341a4fd61878..e0bd12bdebb52 100644 --- a/src/Mod/Draft/draftobjects/array.py +++ b/src/Mod/Draft/draftobjects/array.py @@ -35,6 +35,7 @@ # @{ import math import json +import re from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD as App @@ -389,29 +390,6 @@ def show_and_hide(self, obj, prop): "NumberPolar", "Angle", "IntervalAxis"): obj.setPropertyStatus(pr, "Hidden") - def parse_skip_list(self, obj): - """ - Parses obj.Skip as a list of integers. - The reason for parsing this ourselves instead of using PropertyIntegerList - is so that we can handle failure silently - """ - try: - skip_list_raw = json.loads(obj.Skip) - except json.decoder.JSONDecodeError: - return [] - - if not isinstance(skip_list_raw, list): - return [] - - skip_list = [] - - for s in skip_list_raw: - if isinstance(s, int): - skip_list.append(s) - - return skip_list - - def execute(self, obj): """Execture when the object is created or recomputed.""" if not obj.Base: @@ -432,7 +410,7 @@ def execute(self, obj): "reference.") raise TypeError(_info) - skip_list = self.parse_skip_list(obj) + skip_list = parse_skip_list(obj.Skip) if obj.ArrayType == "ortho": pls = rect_placements(obj.Base.Placement, @@ -577,4 +555,53 @@ def circ_placements(base_placement, return placements + +def parse_skip_list(skip_expression): + """ + Parses a skip expression (as found in obj.Skip) as a list of integers. + + The reason for parsing this ourselves instead of using PropertyIntegerList + is so that we can handle failure silently, and support more advanced indexing. + + Syntax: + ======== + + Skip expressions are expanded in a matlab like way + + Example 1: skip_expression = 1:5 + Will be expanded to [1, 2, 3, 4, 5] + + Example 2: skip_expression = [2:5, 9] + Will be expanded to [2, 3, 4, 5, 9] + + Example 3: skip_expression = [1, 3:2:7, 9] + Will be expanded to [1, 3, 5, 7, 9] + """ + + matches = re.finditer(r"(?P\d+):(?P\d+)(:(?P\d+))*", skip_expression) + + skip_list = [] + for m in matches: + d = m.groupdict() + d = {k:None if d[k] is None else int(d[k]) for k in d} + if d['C']: + skip_list.extend(range(d['A'], d['B'], d['C'])) + else: + skip_list.extend(range(d['A'], d['B'])) + skip_expression = skip_expression.replace(m.group(), '-0.1') # hack: we use a float as a marker in order have valid json, but not a valid index. + + try: + skip_list_raw = json.loads(skip_expression) + except json.decoder.JSONDecodeError: + return skip_list + + if not isinstance(skip_list_raw, list): + return skip_list + + for s in skip_list_raw: + if isinstance(s, int): + skip_list.append(s) + + return skip_list + ## @}