def _move_and_duplicate_furniture(self, data: dir, all_loaded_furniture: list): """ Move and duplicate the furniture depending on the data in the data json dir. After loading each object gets a location based on the data in the json file. Some objects are used more than once these are duplicated and then placed. :param data: json data dir. Should contain "scene", which should contain "room" :param all_loaded_furniture: all objects which have been loaded in _load_furniture_objs """ # this rotation matrix rotates the given quaternion into the blender coordinate system blender_rot_mat = mathutils.Matrix.Rotation(radians(-90), 4, 'X') if "scene" not in data: raise Exception( "There is no scene data in this json file: {}".format( self.json_path)) # for each room for room_id, room in enumerate(data["scene"]["room"]): # for each object in that room for child in room["children"]: if "furniture" in child["instanceid"]: # find the object where the uid matches the child ref id for obj in all_loaded_furniture: if obj["uid"] == child["ref"]: # if the object was used before, duplicate the object and move that duplicated obj if obj["is_used"]: new_obj = duplicate_objects(obj)[0] else: # if it is the first time use the object directly new_obj = obj self.created_objects.append(new_obj) new_obj["is_used"] = True new_obj["room_id"] = room_id new_obj[ "type"] = "Object" # is an object used for the interesting score new_obj["coarse_grained_class"] = new_obj[ "category_id"] # this flips the y and z coordinate to bring it to the blender coordinate system new_obj.location = mathutils.Vector( child["pos"]).xzy new_obj.scale = child["scale"] # extract the quaternion and convert it to a rotation matrix rotation_mat = mathutils.Quaternion( child["rot"]).to_euler().to_matrix().to_4x4() # transform it into the blender coordinate system and then to an euler new_obj.rotation_euler = ( blender_rot_mat @ rotation_mat).to_euler()
def run(self): """ Replaces mesh objects with another mesh objects and scales them accordingly, the replaced objects and the objects to replace with in following steps: 1. Find which object to replace. 2. Place the new object in place of the object to be replaced and scale accordingly. 2. If there is no collision, between that object and the objects in the scene, then do replace and delete the original object. """ self._objects_to_be_replaced = self.config.get_list( "objects_to_be_replaced", []) self._objects_to_replace_with = self.config.get_list( "objects_to_replace_with", []) self._ignore_collision_with = self.config.get_list( "ignore_collision_with", []) # Hide new objects from renderers until they are added for obj in self._objects_to_replace_with: obj.hide_render = True # amount of replacements depends on the amount of objects and the replace ratio amount_of_replacements = int( len(self._objects_to_be_replaced) * self._replace_ratio) if amount_of_replacements == 0: print( "Warning: The amount of objects, which should be replace is zero!" ) amount_of_already_replaced = 0 tries = 0 # tries to replace objects until the amount of requested objects are replaced or the amount # of maximum tries was reached while amount_of_already_replaced < amount_of_replacements and tries < self._max_tries: current_object_to_be_replaced = np.random.choice( self._objects_to_be_replaced) current_object_to_replace_with = np.random.choice( self._objects_to_replace_with) if self._replace_and_edit(current_object_to_be_replaced, current_object_to_replace_with): # Duplicate the added object to be able to add it again duplicates = duplicate_objects(current_object_to_replace_with) if len(duplicates) == 1: duplicate_new_object = duplicates[0] else: raise Exception( "The duplication failed, amount of objects are: {}". format(len(duplicates))) # Copy properties to the newly duplicated object if self._copy_properties: for key, value in current_object_to_be_replaced.items(): duplicate_new_object[key] = value duplicate_new_object.hider_render = False print('Replaced ', current_object_to_replace_with.name, ' by ', duplicate_new_object.name) # Delete the original object and remove it from the list self._objects_to_replace_with.remove( current_object_to_replace_with) bpy.ops.object.select_all(action='DESELECT') current_object_to_replace_with.select_set(True) bpy.ops.object.delete() amount_of_already_replaced += 1 tries += 1 bpy.context.view_layer.update()