def _render_sunskylight(self, name, view): """Get a rendering string for a sunsky light object. This method follows EAFP idiom and will raise exceptions if something goes wrong (missing attribute, inconsistent data...). Parameters: name -- the name of the sunsky light view -- the view of the sunsky light (contains the light data) Returns: a rendering string, obtained from the renderer module """ debug("SunskyLight", name, "Processing") src = view.Source direction = App.Vector(src.SunDirection) turbidity = float(src.Turbidity) # Distance from the sun: distance = App.Units.parseQuantity("151000000 km").Value assert turbidity >= 0,\ translate("Render", "Negative turbidity") assert direction.Length,\ translate("Render", "Sun direction is null") return self._call_renderer("write_sunskylight", name, direction, distance, turbidity)
def _point_at_cb(self, event_cb): """`point_at` method callback. Args: event_cb -- coin event callback object """ event = event_cb.getEvent() if (event.getState() == coin.SoMouseButtonEvent.DOWN and event.getButton() == coin.SoMouseButtonEvent.BUTTON1): # Get point picked_point = event_cb.getPickedPoint() try: point = App.Vector(picked_point.getPoint()) except AttributeError: # No picked point (outside geometry) msg = translate( "Render", "[Point at] Target outside geometry " "-- Aborting") + "\n" App.Console.PrintMessage(msg) else: # Make underlying object point at target point self.fpo.Proxy.point_at(point) msg = translate( "Render", "[Point at] Now pointing at " "({0.x}, {0.y}, {0.z})") + "\n" App.Console.PrintMessage(msg.format(point)) finally: # Remove coin event catcher Gui.ActiveDocument.ActiveView.removeEventCallbackPivy( coin.SoMouseButtonEvent.getClassTypeId(), self.callback)
def check_renderables(renderables): """Assert compliance of a list of renderables.""" assert renderables,\ translate("Render", "Nothing to render") for renderable in renderables: mesh = renderable.mesh assert mesh,\ translate("Render", "Cannot find mesh data") assert mesh.Topology[0] and mesh.Topology[1],\ translate("Render", "Mesh topology is empty") assert mesh.getPointNormals(),\ translate("Render", "Mesh topology has no normals")
def __init__(self, rdrname, **kwargs): """Initialize RendererHandler class. Args: rdrname -- renderer name (str). Must match a renderer plugin name. Keyword args: linear_deflection -- linear deflection (float) to be passed to mesher angular_deflection -- angular deflection (float) to be passed to mesher. transparency_boost -- an integer to augment transparency in implicit material computation """ self.renderer_name = str(rdrname) self.linear_deflection = float(kwargs.get("linear_deflection", .1)) self.angular_deflection = float(kwargs.get("angular_deflection", .524)) self.transparency_boost = float(kwargs.get("transparency_boost", 0)) try: self.renderer_module = import_module("renderers." + rdrname) except ModuleNotFoundError: msg = translate( "Render", "[Render] Import Error: Renderer '%s' not found\n") % rdrname App.Console.PrintError(msg) raise
def point_at(self): """Make this camera point at another object. User will be requested to select an object to point at. """ msg = translate("Render", "[Point at] Please select target (on geometry)") + "\n" App.Console.PrintMessage(msg) self.callback = Gui.ActiveDocument.ActiveView.addEventCallbackPivy( coin.SoMouseButtonEvent.getClassTypeId(), self._point_at_cb)
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)]
def get_rendering_string(self, view): """Provide a rendering string for the view of an object. This method selects the specialized rendering method adapted for 'view', according to its source object type, and calls it. Parameters: view -- the view of the object to render Returns: a rendering string in the format of the external renderer for the supplied 'view' """ try: source = view.Source objtype = getproxyattr(source, "type", "Object") name = str(source.Name) switcher = { "Object": RendererHandler._render_object, "PointLight": RendererHandler._render_pointlight, "Camera": RendererHandler._render_camera, "AreaLight": RendererHandler._render_arealight, "SunskyLight": RendererHandler._render_sunskylight, "ImageLight": RendererHandler._render_imagelight, } res = switcher[objtype](self, name, view) except (AttributeError, TypeError, AssertionError) as err: msg = translate( "Render", "[Render] Cannot render view '{0}': {1} (file {2}, " "line {3} in {4}). Skipping...\n") _, _, exc_traceback = sys.exc_info() framestack = traceback.extract_tb(exc_traceback)[-1] App.Console.PrintWarning(msg.format( getattr(view, "Label", "<No label>"), err, framestack.filename, framestack.lineno, framestack.name)) return "" else: return res
def __init__(self, rdrname, angular_deflection, linear_deflection): """Initialize RendererHandler class. Args: rdrname -- renderer name (str). Must match a renderer plugin name. linear_deflection -- linear deflection (float) to be passed to mesher angular_deflection -- angular deflection (float) to be passed to mesher. """ self.renderer_name = str(rdrname) self.linear_deflection = float(linear_deflection) self.angular_deflection = float(angular_deflection) try: self.renderer_module = import_module("renderers." + rdrname) except ModuleNotFoundError: msg = translate( "Render", "[Render] Import Error: Renderer '%s' not found\n") % rdrname App.Console.PrintError(msg) raise
def message(self): """Give error message.""" msg = translate( "Render", "[Render] Error: Renderer '%s' not found") % self.renderer return msg
translate) # =========================================================================== # Export # =========================================================================== Param = collections.namedtuple("Param", "name type default desc") # IMPORTANT: Please note that, by convention, the first parameter of each # material will be used as default color in fallback mechanisms. # Please be careful to preserve a color-typed field as first parameter of each # material, if you modify an existing material or you add a new one... STD_MATERIALS_PARAMETERS = { "Glass": [ Param("Color", "RGB", (1, 1, 1), translate("Render", "Transmitted color")), Param("IOR", "float", 1.5, translate("Render", "Index of refraction")), ], "Disney": [ Param("BaseColor", "RGB", (0.8, 0.8, 0.8), translate("Render", "Base color")), Param("Subsurface", "float", 0.0, translate("Render", "Subsurface coefficient")), Param("Metallic", "float", 0.0, translate("Render", "Metallic coefficient")), Param("Specular", "float", 0.0, translate("Render", "Specular coefficient")), Param("SpecularTint", "float", 0.0, translate("Render", "Specular tint coefficient")), Param("Roughness", "float", 0.0, translate("Render", "Roughness coefficient")),
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