From 883b8a523c63027f2f6c91650385d47edba5521b Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Wed, 2 Feb 2022 17:51:40 +1100 Subject: [PATCH] Material node trees compliant with basic X3D multitextures are now stored in IFC --- .../api/style/add_surface_textures.py | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/ifcopenshell-python/ifcopenshell/api/style/add_surface_textures.py diff --git a/src/ifcopenshell-python/ifcopenshell/api/style/add_surface_textures.py b/src/ifcopenshell-python/ifcopenshell/api/style/add_surface_textures.py new file mode 100644 index 00000000000..d6acd228db4 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/style/add_surface_textures.py @@ -0,0 +1,92 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2022 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import ifcopenshell +import ifcopenshell.api + + +class Usecase: + def __init__(self, file, **settings): + # TODO: This usecase currently depends on Blender's data model + self.file = file + # Textures is assumed to be a dictionary of texture maps. + # The key is the texture map name, and the value is the last texture manipulation in the graph. + self.settings = {"textures": None} + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + self.textures = [] + for texture, node in self.settings["textures"].items(): + parameters = self.get_default_parameters(texture) + self.traverse_node(node, parameters) + return list(reversed(self.textures)) + + def get_default_parameters(self, texture): + return {"mode": "REPLACE", "source": "", "function": "", "rgb": "1 1 1", "alpha": "1", "texture": texture} + + def traverse_node(self, node, parameters): + if node.type == "MIX_RGB": + if node.blend_type == "MIX": + parameters["mode"] = "REPLACE" + elif node.blend_type == "ADD": + parameters["mode"] = "ADD" + elif node.blend_type == "MULTIPLY": + parameters["mode"] = "MODULATE" + + if not node.inputs["Fac"].links: + if parameters["mode"] == "REPLACE": + parameters["mode"] = "BLEND" + parameters["mode"] += "FACTORALPHA" + parameters["alpha"] = str(node.inputs["Fac"].default_value) + + if node.inputs["Color1"].links and node.inputs["Color2"].links: + self.traverse_node(node.inputs["Color2"].links[0].from_node, parameters) + self.traverse_node( + node.inputs["Color1"].links[0].from_node, self.get_default_parameters(parameters["texture"]) + ) + elif node.inputs["Color1"].links: + parameters["rgb"] = " ".join(map(str, list(node.inputs["Color2"].default_value)[0:3])) + parameters["source"] = "FACTOR" + self.traverse_node(node.inputs["Color1"].links[0].from_node, parameters) + elif node.inputs["Color2"].links: + parameters["rgb"] = " ".join(map(str, list(node.inputs["Color1"].default_value)[0:3])) + parameters["source"] = "FACTOR" + self.traverse_node(node.inputs["Color2"].links[0].from_node, parameters) + elif node.type == "VECT_MATH": + # TODO Handle 2X, 4X, and signed + pass + elif node.type == "INVERT": + parameters["function"] = "COMPLEMENT" if parameters["function"] == "" else "" + elif node.type == "TEX_IMAGE": + return self.create_surface_texture(node, parameters) + else: + # TODO keep traversing backwards + pass + + def create_surface_texture(self, node, parameters): + self.textures.append( + self.file.create_entity( + "IfcImageTexture", + RepeatS=node.extension == "REPEAT", + RepeatT=node.extension == "REPEAT", + Mode=parameters["mode"], + Parameter=[parameters[p] for p in ["source", "function", "rgb", "alpha", "texture"]], + URLReference=node.image.filepath, + ) + )