from __future__ import annotations from collections.abc import Iterable, Mapping def property_specs_from_scdm_cache( cache: Mapping[str, object], *, selected_face_ids: Iterable[int] = (), selected_edge_ids: Iterable[int] = (), selected_solid_ids: Iterable[int] = (), execution_ready: bool | Iterable[str] = False, ) -> list[dict[str, object]]: face_ids = {int(item) for item in selected_face_ids} edge_ids = {int(item) for item in selected_edge_ids} solid_ids = {int(item) for item in selected_solid_ids} if not face_ids and not edge_ids and not solid_ids: return [] objects = cache.get("objects") if not isinstance(objects, list): return [] specs: list[dict[str, object]] = [] for item in objects: if not isinstance(item, Mapping) or not _object_matches( item, face_ids=face_ids, edge_ids=edge_ids, solid_ids=solid_ids, ): continue capabilities = item.get("capabilities") if not isinstance(capabilities, list): continue for capability in capabilities: if isinstance(capability, Mapping): if str(capability.get("key") or "") in {"pattern.segment_spacing", "pattern.instance_position"}: continue spec = _capability_spec(item, capability, execution_ready=execution_ready) if spec is not None: specs.append(spec) specs.extend( _pattern_instance_position_specs( item, selected_face_ids=face_ids, selected_solid_ids=solid_ids, execution_ready=execution_ready, ) ) specs.extend(_pattern_segment_spacing_specs(item, execution_ready=execution_ready)) return specs def _object_matches( raw_object: Mapping[str, object], *, face_ids: set[int], edge_ids: set[int], solid_ids: set[int], ) -> bool: signature = raw_object.get("geometrySignature") if not isinstance(signature, Mapping): return False object_faces = set(_int_values(signature.get("faceIds"))) object_faces.update(_int_values(signature.get("supportFaceIds"))) object_edges = set(_int_values(signature.get("edgeIds"))) if (face_ids and object_faces & face_ids) or (edge_ids and object_edges & edge_ids): return True if not solid_ids: return False object_type = str(raw_object.get("objectType") or "").strip().lower() if object_type not in {"pattern", "linear_pattern"}: return False return bool(_pattern_local_solid_ids(signature) & solid_ids) def _capability_spec( raw_object: Mapping[str, object], capability: Mapping[str, object], *, execution_ready: bool | Iterable[str], ) -> dict[str, object] | None: key = str(capability.get("key") or "").strip() label = str(capability.get("displayName") or key).strip() if not key or not label: return None value_kind = str(capability.get("valueKind") or "number") current = capability.get("currentValue") value_type = _value_type(value_kind, key) signature = raw_object.get("geometrySignature") if isinstance(raw_object.get("geometrySignature"), Mapping) else {} unit_scale = _unit_scale(signature if isinstance(signature, Mapping) else {}) current_display = _display_value(current, key=key, value_type=value_type, unit_scale=unit_scale) command_value = value_type == "command" current_text = "可执行" if command_value else _format_value(current_display, value_type=value_type) target_text = "执行" if command_value else _format_value(current_display, value_type=value_type) capability_block = str(capability.get("blockReason") or "").strip() object_block = str(raw_object.get("blockReason") or "").strip() block_reason = capability_block or object_block if not command_value and not _current_value_available(current_display, value_type=value_type): block_reason = block_reason or f"SCDM 已识别“{label}”,但没有返回可用于编辑的当前值。" backend_operation = str(capability.get("backendOperation") or "") post_check = str(capability.get("postCheck") or "") max_value = _display_max_value(key=key, signature=signature if isinstance(signature, Mapping) else {}, unit_scale=unit_scale) range_hint = "来源:SCDM 结构化识别结果。执行前仍需生成 edit job,并在结果 STEP 上做 OCCT 校验和目标值回测。" if key == "pattern.spacing" and max_value is not None: range_hint = f"该阵列受承载面范围限制,保持阵列中心不变时最大间距约 {max_value:g};超过后会跑出承载面。" can_execute = bool(_capability_execution_ready(key, execution_ready) and capability.get("editable", True) and not block_reason) if can_execute: disabled_tip = "" enabled_tip = ( f"SCDM 已识别“{label}”可由 {backend_operation or '后端命令'} 修改;" f"执行后会用 {post_check or '结果回测'} 校验。" ) elif block_reason: enabled_tip = "" disabled_tip = f"SCDM 已识别该对象,但当前能力被阻止:{block_reason}" else: enabled_tip = "" disabled_tip = "SCDM 已识别该参数,但 S5 修改执行器还没有接入;当前只作为后端识别结果缓存,不开放执行。" return { "key": f"scdm:{key}", "label": label, "current_raw": current_display if current_display is not None else "", "scdm_current_raw": current if current is not None else "", "scdm_unit_scale": unit_scale, "current_text": current_text, "target_text": target_text, "editable": True, "enabled": can_execute, "status_text": "可修改" if can_execute else "暂未接入", "scope_text": str(capability.get("defaultIntent") or "SCDM"), "action": "apply_scdm_property_edit", "value_type": value_type, "enabled_tip": enabled_tip, "disabled_tip": disabled_tip, "range_hint": range_hint, "min_value": 0.0 if value_type == "positive" else None, "min_exclusive": True if value_type == "positive" else False, "max_value": max_value, "scdm_object_id": raw_object.get("objectId"), "scdm_source_backend_id": raw_object.get("sourceBackendId"), "scdm_capability_key": key, "scdm_backend_operation": backend_operation, "scdm_post_check": post_check, "scdm_geometry_signature": signature if isinstance(signature, Mapping) else {}, } def _unit_scale(signature: Mapping[str, object]) -> float: try: value = float(str(signature.get("localUnitScale")).strip()) except (TypeError, ValueError): return 1.0 return value if value > 0 else 1.0 def _display_value(value: object, *, key: str, value_type: str, unit_scale: float) -> object: if unit_scale <= 0 or abs(unit_scale - 1.0) <= 1.0e-12 or not _uses_length_units(key, value_type): return value if value_type == "vector3": values = _float_values(value) if len(values) == 3: return [item / unit_scale for item in values] return value try: return float(str(value).strip()) / unit_scale except (TypeError, ValueError): return value def _uses_length_units(key: str, value_type: str) -> bool: if value_type == "vector3": return True suffixes = ( ".diameter", ".radius", ".offset", ".width", ".depth", ".height", ".distance", ".thickness", ".spacing", ".segment_spacing", ".position", ) return key.endswith(suffixes) def _display_max_value(*, key: str, signature: Mapping[str, object], unit_scale: float) -> float | None: if key != "pattern.spacing": return None fit = signature.get("supportPatternFit") if not isinstance(fit, Mapping): return None value = fit.get("maxSpacingLocal") try: result = float(str(value).strip()) except (TypeError, ValueError): backend_value = fit.get("maxSpacing") try: return float(str(backend_value).strip()) / unit_scale if unit_scale > 0 else None except (TypeError, ValueError): return None return result if result > 0 else None def _pattern_segment_spacing_specs( raw_object: Mapping[str, object], *, execution_ready: bool | Iterable[str], ) -> list[dict[str, object]]: if str(raw_object.get("objectType") or "").strip().lower() != "linear_pattern": return [] signature = raw_object.get("geometrySignature") if not isinstance(signature, Mapping): return [] axis = _unit_vector(_float_values(signature.get("axis"))) if len(axis) != 3: return [] instances = _sorted_pattern_instances(signature, axis) if len(instances) < 2: return [] unit_scale = _unit_scale(signature) can_execute = bool(_capability_execution_ready("pattern.segment_spacing", execution_ready) and not str(raw_object.get("blockReason") or "").strip()) specs: list[dict[str, object]] = [] for segment_index in range(len(instances) - 1): # UI 上展示的是相邻实例之间的“段间距”,不是整列统一 spacing。 # 每一段都带自己的移动语义和安全范围,避免“第 1-2 间距”改成整列平移。 left = instances[segment_index] right = instances[segment_index + 1] left_label = _segment_instance_label(left, segment_index + 1) right_label = _segment_instance_label(right, segment_index + 2) segment_label = f"{left_label}-{right_label}间距" current = max(0.0, float(right["projection"]) - float(left["projection"])) if current <= 0: continue current_display = current / unit_scale if unit_scale > 0 else current scope_modes = _segment_scope_modes( signature, instances, segment_index, current, current_display, unit_scale, left_label=left_label, right_label=right_label, segment_label=segment_label, can_execute=can_execute, ) default_mode = scope_modes.get("fix_left_move_right", {}) if isinstance(scope_modes, Mapping) else {} max_display = default_mode.get("max_value") range_hint = str(default_mode.get("range_hint") or "") enabled_tip = str(default_mode.get("enabled_tip") or range_hint) segment_signature = default_mode.get("scdm_geometry_signature") if not isinstance(segment_signature, Mapping): segment_signature = _segment_signature( signature, segment_index, current, unit_scale, left_label=left_label, right_label=right_label, moving_side="after", motion_semantics="fix_left_move_right_group", ) specs.append( { "key": f"scdm:pattern.segment_spacing:{segment_index}", "label": segment_label, "current_raw": current_display, "scdm_current_raw": current, "scdm_unit_scale": unit_scale, "current_text": _format_value(current_display, value_type="positive"), "target_text": _format_value(current_display, value_type="positive"), "editable": True, "enabled": can_execute, "status_text": "可修改" if can_execute else "暂未接入", "scope_text": "固定前项,移动后侧", "scope_modes": scope_modes, "scope_default": "fix_left_move_right", "action": "apply_scdm_property_edit", "value_type": "positive", "enabled_tip": enabled_tip, "disabled_tip": "" if can_execute else "SCDM 已识别该局部间距,但当前修改执行器尚未开放。", "range_hint": range_hint, "min_value": 0.0, "min_exclusive": True, "max_value": max_display, "scdm_object_id": raw_object.get("objectId"), "scdm_source_backend_id": raw_object.get("sourceBackendId"), "scdm_capability_key": "pattern.segment_spacing", "scdm_backend_operation": "change_pattern_segment_spacing", "scdm_post_check": "target_pattern_segment_spacing", "scdm_geometry_signature": segment_signature, } ) return specs def _pattern_instance_position_specs( raw_object: Mapping[str, object], *, selected_face_ids: set[int], selected_solid_ids: set[int], execution_ready: bool | Iterable[str], ) -> list[dict[str, object]]: if str(raw_object.get("objectType") or "").strip().lower() not in {"pattern", "linear_pattern"}: return [] signature = raw_object.get("geometrySignature") if not isinstance(signature, Mapping): return [] unit_scale = _unit_scale(signature) can_execute = bool(_capability_execution_ready("pattern.instance_position", execution_ready) and not str(raw_object.get("blockReason") or "").strip()) specs: list[dict[str, object]] = [] instances = _pattern_instances_in_original_order(signature) for ordinal, instance in enumerate(instances, start=1): if selected_face_ids and not (set(_int_values(instance.get("faceIds"))) & selected_face_ids): continue if selected_solid_ids and not (_instance_local_solid_ids(instance) & selected_solid_ids): continue center = _float_values(instance.get("center") or instance.get("instanceCenter")) if len(center) != 3: continue label = _segment_instance_label({"source": instance}, ordinal) current_display = [value / unit_scale for value in center] if unit_scale > 0 else list(center) instance_signature = _pattern_instance_signature(signature, instance, unit_scale=unit_scale, label=label) locatable = _pattern_instance_has_locator(instance_signature) enabled = bool(can_execute and locatable) disabled_tip = "" if not can_execute: disabled_tip = "SCDM 已识别该阵列实例,但当前修改执行器尚未开放。" elif not locatable: disabled_tip = "SCDM 已识别该阵列实例,但缓存里没有可定位的 Face / Body / Component,不能稳定移动。" range_hint = f"移动阵列实例:只平移 {label},不自动保持整体阵列等距;需要保持间距时请使用“阵列间距”或“局部间距”。" specs.append( { "key": f"scdm:pattern.instance_position:{ordinal - 1}", "label": f"{label}位置", "current_raw": current_display, "scdm_current_raw": center, "scdm_unit_scale": unit_scale, "current_text": _format_value(current_display, value_type="vector3"), "target_text": _format_value(current_display, value_type="vector3"), "editable": True, "enabled": enabled, "status_text": "可修改" if enabled else "暂未接入", "scope_text": "只移动该实例", "action": "apply_scdm_property_edit", "value_type": "vector3", "enabled_tip": range_hint if enabled else "", "disabled_tip": disabled_tip, "range_hint": range_hint, "min_value": None, "min_exclusive": False, "max_value": None, "scdm_object_id": raw_object.get("objectId"), "scdm_source_backend_id": raw_object.get("sourceBackendId"), "scdm_capability_key": "pattern.instance_position", "scdm_backend_operation": "move_pattern_instance", "scdm_post_check": "target_pattern_instance_center", "scdm_geometry_signature": instance_signature, } ) return specs def _pattern_instances_in_original_order(signature: Mapping[str, object]) -> list[Mapping[str, object]]: value = signature.get("patternInstances") if not isinstance(value, (list, tuple)): return [] return [item for item in value if isinstance(item, Mapping)] def _pattern_instance_signature( signature: Mapping[str, object], instance: Mapping[str, object], *, unit_scale: float, label: str, ) -> dict[str, object]: result = dict(instance) result["objectType"] = "pattern_instance" result["displayLabel"] = label result["patternObjectType"] = signature.get("objectType") result["patternKind"] = signature.get("patternKind") result["instanceKind"] = instance.get("instanceKind") or signature.get("instanceKind") result["axis"] = signature.get("axis") result["localUnitScale"] = unit_scale center = _float_values(instance.get("center") or instance.get("instanceCenter")) if len(center) == 3: result["center"] = center result["instanceCenter"] = center return result def _pattern_instance_has_locator(signature: Mapping[str, object]) -> bool: if signature.get("componentLocators") or signature.get("bodyLocators") or signature.get("scdmFaceLocators"): return True if _int_values(signature.get("faceOrdinals")) or _int_values(signature.get("globalFaceOrdinals")): return True if _int_or_none(signature.get("faceOrdinal")) is not None or _int_or_none(signature.get("globalFaceOrdinal")) is not None: return True instance_kind = str(signature.get("instanceKind") or "").strip().lower() return instance_kind in {"body", "part", "component"} and _int_or_none(signature.get("bodyIndex")) is not None def _pattern_local_solid_ids(signature: Mapping[str, object]) -> set[int]: ids = set(_int_values(signature.get("localSolidIds"))) local_solid = _int_or_none(signature.get("localSolidId")) if local_solid is not None: ids.add(local_solid) ids.update(_int_values(signature.get("bodyIndices"))) body_index = _int_or_none(signature.get("bodyIndex")) if body_index is not None: ids.add(body_index) for instance in _pattern_instances_in_original_order(signature): ids.update(_instance_local_solid_ids(instance)) return ids def _instance_local_solid_ids(instance: Mapping[str, object]) -> set[int]: ids = set(_int_values(instance.get("localSolidIds"))) local_solid = _int_or_none(instance.get("localSolidId")) if local_solid is not None: ids.add(local_solid) body_index = _int_or_none(instance.get("bodyIndex")) if body_index is not None: ids.add(body_index) return ids def _sorted_pattern_instances(signature: Mapping[str, object], axis: list[float]) -> list[dict[str, object]]: value = signature.get("patternInstances") if not isinstance(value, (list, tuple)): return [] result: list[dict[str, object]] = [] for index, item in enumerate(value): if not isinstance(item, Mapping): continue center = _float_values(item.get("center") or item.get("instanceCenter")) if len(center) != 3: continue result.append( { "index": index, "source": item, "center": center, "projection": _point_projection(center, axis), } ) # 用阵列轴投影排序,比原始 cache 顺序更接近用户看到的左到右/前到后顺序。 result.sort(key=lambda item: float(item["projection"])) return result def _segment_max_spacing_display( signature: Mapping[str, object], instances: list[dict[str, object]], segment_index: int, current_display: float, unit_scale: float, *, moving_side: str = "after", ) -> float | None: fit = signature.get("supportPatternFit") if not isinstance(fit, Mapping): return None projection_min = _float_or_none(fit.get("supportProjectionMinLocal")) projection_max = _float_or_none(fit.get("supportProjectionMaxLocal")) member_span = _float_or_none(fit.get("memberSpanLocal")) if projection_min is None or projection_max is None or member_span is None or member_span <= 0: return None first_projection = float(instances[0]["projection"]) last_projection = float(instances[-1]["projection"]) first_projection_display = first_projection / unit_scale if unit_scale > 0 else first_projection last_projection_display = last_projection / unit_scale if unit_scale > 0 else last_projection backward_capacity = first_projection_display - projection_min - (member_span * 0.5) forward_capacity = projection_max - (member_span * 0.5) - last_projection_display if moving_side in {"before", "left", "single_left", "only_left"}: extra = backward_capacity elif moving_side in {"split", "both", "center"}: extra = 2.0 * min(backward_capacity, forward_capacity) else: extra = forward_capacity return max(current_display, current_display + max(0.0, extra)) def _segment_scope_modes( signature: Mapping[str, object], instances: list[dict[str, object]], segment_index: int, current_backend: float, current_display: float, unit_scale: float, *, left_label: str, right_label: str, segment_label: str, can_execute: bool, ) -> dict[str, dict[str, object]]: modes: dict[str, dict[str, object]] = {} # 同一个“间距”参数有多种建模意图:固定哪一侧、是否保持中心。 # 这些模式会直接进入 scdm_edit_job,不能只作为 UI 文案存在。 for key, label, moving_side, semantics, description in ( ( "fix_left_move_right", "固定前项,移动后侧", "after", "fix_left_move_right_group", f"固定 {left_label},平移 {right_label} 及其右侧所有阵列成员,右侧已有间距保持不变。", ), ( "fix_right_move_left", "固定后项,移动前侧", "before", "fix_right_move_left_group", f"固定 {right_label},平移 {left_label} 及其左侧所有阵列成员,左侧已有间距保持不变。", ), ( "split_keep_center", "两侧均分,中心不变", "split", "split_groups_keep_segment_center", f"{left_label} 及左侧向前移动一半,{right_label} 及右侧向后移动一半,保持这段间距中心不变。", ), ): max_display = _segment_max_spacing_display( signature, instances, segment_index, current_display, unit_scale, moving_side=moving_side, ) mode_signature = _segment_signature( signature, segment_index, current_backend, unit_scale, left_label=left_label, right_label=right_label, moving_side=moving_side, motion_semantics=semantics, max_display=max_display, ) range_hint = f"{label}:{description} 对象段:{segment_label},沿阵列方向由 {left_label} 到 {right_label}。" if max_display is not None and max_display > 0: range_hint += f" 当前支撑面约允许该策略最大间距 {max_display:g}。" modes[key] = { "label": label, "enabled": can_execute, "enabled_tip": range_hint, "disabled_tip": "" if can_execute else "SCDM 已识别该局部间距,但当前修改执行器尚未开放。", "range_hint": range_hint, "max_value": max_display, "scdm_geometry_signature": mode_signature, } for key, label, moving_side, semantics, moved_label, neighbor_warning in ( ( "move_single_left", "只移动前项", "single_left", "move_only_left_instance", left_label, "会改变它与左侧相邻成员的距离", ), ( "move_single_right", "只移动后项", "single_right", "move_only_right_instance", right_label, "会改变它与右侧相邻成员的距离", ), ): max_display = _segment_max_spacing_display( signature, instances, segment_index, current_display, unit_scale, moving_side=moving_side, ) mode_signature = _segment_signature( signature, segment_index, current_backend, unit_scale, left_label=left_label, right_label=right_label, moving_side=moving_side, motion_semantics=semantics, max_display=max_display, ) range_hint = ( f"{label}:只平移 {moved_label},把 {left_label}-{right_label} 这段调到目标间距;" f"{neighbor_warning},不用于保持整列等距。对象段:{segment_label}。" ) if max_display is not None and max_display > 0: range_hint += f" 当前支撑面约允许该策略最大间距 {max_display:g}。" modes[key] = { "label": label, "enabled": can_execute, "enabled_tip": range_hint if can_execute else "", "disabled_tip": "" if can_execute else "SCDM 已识别该局部间距,但当前修改执行器尚未开放。", "range_hint": range_hint, "max_value": max_display, "scdm_geometry_signature": mode_signature, } return modes def _segment_signature( signature: Mapping[str, object], segment_index: int, current_backend: float, unit_scale: float, *, left_label: str, right_label: str, moving_side: str, motion_semantics: str, max_display: object = None, ) -> dict[str, object]: result = dict(signature) segment_fit = dict(result.get("supportPatternFit") if isinstance(result.get("supportPatternFit"), Mapping) else {}) max_number = _float_or_none(max_display) if max_number is not None and max_number > 0: segment_fit["maxSegmentSpacingLocal"] = max_number segment_fit["maxSegmentSpacing"] = max_number * unit_scale if unit_scale > 0 else max_number result["supportPatternFit"] = segment_fit result["segmentIndex"] = segment_index result["segmentLabel"] = f"{left_label}-{right_label}" result["segmentLeftLabel"] = left_label result["segmentRightLabel"] = right_label result["segmentSpacing"] = current_backend result["movingSide"] = moving_side result["motionSemantics"] = motion_semantics axis = _unit_vector(_float_values(signature.get("axis"))) instances = _sorted_pattern_instances(signature, axis) if len(axis) == 3 else [] if segment_index < len(instances) - 1: result["segmentLeft"] = _segment_instance_reference(instances[segment_index], label=left_label) result["segmentRight"] = _segment_instance_reference(instances[segment_index + 1], label=right_label) result["localUnitScale"] = unit_scale return result def _segment_instance_reference(item: Mapping[str, object], *, label: str = "") -> dict[str, object]: source = item.get("source") if not isinstance(source, Mapping): return {} return { "displayLabel": label, "sourceObjectId": source.get("sourceObjectId"), "faceIds": _int_values(source.get("faceIds")), "bodyIndex": _int_or_none(source.get("bodyIndex")), "componentLocators": source.get("componentLocators") or source.get("bodyLocators") or [], } def _segment_instance_label(item: Mapping[str, object], ordinal: int) -> str: source = item.get("source") if not isinstance(source, Mapping): return f"阵列成员{ordinal}" instance_kind = str(source.get("instanceKind") or "").strip().lower() if instance_kind in {"body", "part", "component"}: local_solid_ids = sorted(set(_int_values(source.get("localSolidIds") or [source.get("localSolidId")]))) if local_solid_ids: return f"Solid{local_solid_ids[0]}{'组' if len(local_solid_ids) > 1 else ''}" local_part_ids = sorted(set(_int_values(source.get("localPartIds") or [source.get("localPartId")]))) if local_part_ids: return f"Part{local_part_ids[0]}{'组' if len(local_part_ids) > 1 else ''}" component_label = _component_locator_label(source.get("componentLocators") or source.get("bodyLocators"), include_index=False) if component_label: return component_label body_index = _int_or_none(source.get("bodyIndex")) if body_index is not None: return f"Solid{body_index}" face_ids = sorted(set(_int_values(source.get("faceIds")))) if face_ids: return f"Face{face_ids[0]}{'组' if len(face_ids) > 1 else ''}" component_label = _component_locator_label(source.get("componentLocators") or source.get("bodyLocators")) if component_label: return component_label body_index = _int_or_none(source.get("bodyIndex")) if body_index is not None: return f"Solid{body_index}" source_id = str(source.get("sourceObjectId") or "").strip() if source_id: return source_id return f"阵列成员{ordinal}" def _component_locator_label(value: object, *, include_index: bool = True) -> str: if not isinstance(value, (list, tuple)): return "" for locator in value: if not isinstance(locator, Mapping): continue for key in ("componentName", "name", "displayName"): text = str(locator.get(key) or "").strip() if text: return text if not include_index: return "" for locator in value: if not isinstance(locator, Mapping): continue component_index = _int_or_none(locator.get("componentIndex")) if component_index is not None: return f"组件{component_index + 1}" return "" def _unit_vector(values: list[float]) -> list[float]: if len(values) != 3: return [] length = sum(item * item for item in values) ** 0.5 if length <= 1.0e-12: return [] return [item / length for item in values] def _point_projection(point: list[float], axis: list[float]) -> float: return sum(float(point[index]) * float(axis[index]) for index in range(3)) def _float_or_none(value: object) -> float | None: try: return float(str(value).strip()) except (TypeError, ValueError): return None def _value_type(value_kind: str, key: str) -> str: if value_kind == "vector3": return "vector3" if value_kind == "command": return "command" positive_suffixes = (".diameter", ".radius", ".width", ".depth", ".height", ".distance", ".thickness", ".spacing", ".segment_spacing") if key.endswith(positive_suffixes): return "positive" return "number" def _capability_execution_ready(key: str, execution_ready: bool | Iterable[str]) -> bool: if isinstance(execution_ready, bool): return execution_ready try: return key in {str(item) for item in execution_ready} except TypeError: return False def _format_value(value: object, *, value_type: str) -> str: if value is None: return "" if value_type == "vector3": values = _float_values(value) return f"({values[0]:g}, {values[1]:g}, {values[2]:g})" if len(values) == 3 else "" if isinstance(value, float): return f"{value:g}" return str(value) def _current_value_available(value: object, *, value_type: str) -> bool: if value is None or value == "": return False if value_type == "vector3": return len(_float_values(value)) == 3 if value_type in {"number", "positive"}: try: return float(str(value).strip()) > 0 if value_type == "positive" else True except (TypeError, ValueError): return False return True def _float_values(value: object) -> list[float]: if isinstance(value, (str, bytes)) or value is None: return [] try: values = list(value) # type: ignore[arg-type] except TypeError: return [] result: list[float] = [] for item in values[:3]: try: result.append(float(item)) except (TypeError, ValueError): return [] return result def _int_values(value: object) -> list[int]: if isinstance(value, (str, bytes)) or value is None: return [] try: values = list(value) # type: ignore[arg-type] except TypeError: return [] result: list[int] = [] for item in values: try: result.append(int(item)) except (TypeError, ValueError): continue return result def _int_or_none(value: object) -> int | None: try: return int(value) except (TypeError, ValueError): return None __all__ = ["property_specs_from_scdm_cache"]