def _get_material(base_renderable, upper_material):
    """Get material from a base renderable and an upper material."""
    upper_mat_is_multimat = is_multimat(upper_material)

    return (base_renderable.material if
            (upper_material is None
             or upper_mat_is_multimat) else upper_material)
def _get_rends_from_window(obj, name, material, mesher, **kwargs):
    """Get renderables from an Window object (from Arch workbench).

    Parameters:
        obj -- the Window object
        name -- the name assigned to the Window object for rendering
        material -- the material for the Window object (should be a
                    multimaterial)
        mesher -- a callable object which converts a shape into a mesh

    Returns:
        A list of renderables for the Window object
    """
    # Subobjects names
    window_parts = obj.WindowParts
    if not window_parts and hasattr(obj, "CloneOf") and obj.CloneOf:
        # Workaround: if obj is a window Clone, WindowsParts is unfortunately
        # not replicated (must be a bug...). Therefore we look at base's
        # WindowsParts
        window_parts = obj.CloneOf.WindowParts
    subnames = window_parts[0::5]  # Names every 5th item...
    names = ["%s_%s" % (name, s.replace(' ', '_')) for s in subnames]

    # Subobjects meshes
    meshes = [mesher(s) for s in obj.Shape.childShapes()]

    # Subobjects colors
    transparency_boost = kwargs.get("transparency_boost", 0)
    faces_len = [len(s.Faces) for s in obj.Shape.Solids]
    if obj.ViewObject is not None:  # Gui is up
        colors = [
            _boost_tp(obj.ViewObject.DiffuseColor[i], transparency_boost)
            for i in itertools.accumulate([0] + faces_len[:-1])
        ]
    else:
        colors = [RGBA(0.8, 0.8, 0.8, 1)] * len(subnames)

    # Subobjects materials
    if material is not None:
        assert is_multimat(material), "Multimaterial expected"
        mats_dict = dict(zip(material.Names, material.Materials))
        mats = [mats_dict.get(s) for s in subnames]
        if [m for m in mats if not m]:
            msg = translate("Render", "Incomplete multimaterial (missing {})")
            missing_mats = ', '.join(set(subnames) - mats_dict.keys())
            warn("Window", obj.Label, msg.format(missing_mats))
    else:
        mats = [None] * len(subnames)

    # Build renderables
    return [Renderable(*r) for r in zip(names, meshes, mats, colors)]
Exemple #3
0
def _get_rends_from_wall(obj, name, material, mesher, **kwargs):
    """Get renderables from an Window object (from Arch workbench).

    Parameters:
        obj -- the Window object
        name -- the name assigned to the Window object for rendering
        material -- the material for the Window object (should be a
                    multimaterial)
        mesher -- a callable object which converts a shape into a mesh

    Returns:
        A list of renderables for the Window object
    """
    if material is None or not is_multimat(material):
        # No multimaterial: handle wall as a plain Part::Feature
        return _get_rends_from_partfeature(obj, name, material, mesher,
                                           **kwargs)

    shapes = obj.Shape.childShapes()

    # Subobjects names
    names = ["{}_{}".format(name, i) for i in range(len(shapes))]

    # Subobjects meshes
    meshes = [mesher(s) for s in shapes]

    # Subobjects materials
    materials = material.Materials

    # Subobjects colors
    tp_boost = kwargs.get("transparency_boost", 0)
    colors = [
        _boost_tp(RGBA(*m.Color[0:3], m.Transparency), tp_boost)
        for m in materials
    ]

    # Build renderables
    return [Renderable(*r) for r in zip(names, meshes, materials, colors)]
def get_renderables(obj, name, upper_material, mesher, **kwargs):
    """Get the renderables from a FreeCAD object.

    A renderable is a tuple (name, mesh, material). There can be
    several renderables for one object, for instance if the object is a
    compound of subobjects, so the result of this function is a **list**
    of renderables.
    If this function does not know how to extract renderables from the
    given object, a TypeError is raised

    Parameters:
        obj -- the FreeCAD object from which to extract the renderables
        name -- the name of the object
        upper_material -- the FreeCAD material inherited from the upper
            level
        mesher -- a callable which can convert a shape into a mesh

    Keywords arguments:
        ignore_unknown -- a flag to prevent exception raising if 'obj' is
            of no renderable type
        transparency_boost -- a factor (positive integer) to boost
            transparency in shape color

    Returns:
        A list of renderables
    """
    obj_is_applink = obj.isDerivedFrom("App::Link")
    obj_is_partfeature = obj.isDerivedFrom("Part::Feature")
    obj_is_meshfeature = obj.isDerivedFrom("Mesh::Feature")
    obj_is_app_part = obj.isDerivedFrom("App::Part")
    obj_type = getproxyattr(obj, "Type", "")

    mat = (getattr(obj, "Material", None)
           if upper_material is None else upper_material)
    mat = mat if is_valid_material(mat) or is_multimat(mat) else None
    del upper_material  # Should not be used after this point...

    label = getattr(obj, "Label", name)
    ignore_unknown = bool(kwargs.get("ignore_unknown", False))
    transparency_boost = int(kwargs.get("transparency_boost", 0))

    # Link (plain)
    if obj_is_applink and not obj.ElementCount:
        debug("Object", label, "'Link (plain)' detected")
        renderables = \
            _get_rends_from_plainapplink(obj, name, mat, mesher, **kwargs)

    # Link (array)
    elif obj_is_applink and obj.ElementCount:
        debug("Object", label, "'Link (array)' detected")
        renderables = \
            _get_rends_from_elementlist(obj, name, mat, mesher, **kwargs)

    # Array, PathArray
    elif obj_is_partfeature and obj_type in ("Array", "PathArray"):
        debug("Object", label, "'%s' detected" % obj_type)
        expand_array = getattr(obj, "ExpandArray", False)
        renderables = (_get_rends_from_array(obj, name, mat, mesher, **kwargs)
                       if not expand_array else _get_rends_from_elementlist(
                           obj, name, mat, mesher, **kwargs))

    # Window
    elif obj_is_partfeature and obj_type == "Window":
        debug("Object", label, "'Window' detected")
        renderables = _get_rends_from_window(obj, name, mat, mesher, **kwargs)

    # Wall
    elif obj_is_partfeature and obj_type == "Wall":
        debug("Object", label, "'Wall' detected")
        renderables = _get_rends_from_wall(obj, name, mat, mesher, **kwargs)

    # App part
    elif obj_is_app_part:
        debug("Object", label, "'App::Part' detected")
        renderables = _get_rends_from_part(obj, name, mat, mesher, **kwargs)

    # Plain part feature
    elif obj_is_partfeature:
        debug("Object", label, "'Part::Feature' detected")
        renderables = _get_rends_from_feature(obj, name, mat, mesher, **kwargs)

    # Mesh
    elif obj_is_meshfeature:
        debug("Object", label, "'Mesh::Feature' detected")
        color = _get_shapecolor(obj, transparency_boost)
        renderables = [Renderable(name, obj.Mesh, mat, color)]

    # Unhandled
    else:
        renderables = []
        if not ignore_unknown:
            ascendants = ", ".join(obj.getAllDerivedFrom())
            msg = translate("Render",
                            "Unhandled object type (%s)" % ascendants)
            raise TypeError(msg)
        debug("Object", label, "Not renderable")

    return renderables