Source code for ddg.halfedge._io

import json

import numpy as np

import ddg


class HalfedgeEncoder(json.JSONEncoder):
    def __init__(self, vertex_attrs=[], edge_attrs=[], face_attrs=[], **kwargs):
        super(HalfedgeEncoder, self).__init__(**kwargs)
        self.vertex_slots = ["edge"]
        self.vertex_attrs = vertex_attrs
        self.edge_slots = ["pre", "nex", "opp", "head", "face"]
        self.edge_attrs = edge_attrs
        self.face_slots = ["edge"]
        self.face_attrs = face_attrs

    def default(self, obj):
        if isinstance(obj, ddg.halfedge.Surface):
            obj.verts.add_attribute("json_idx")
            obj.edges.add_attribute("json_idx")
            obj.faces.add_attribute("json_idx")
            for i, v in enumerate(obj.verts):
                v.json_idx = i

            for i, e in enumerate(obj.edges):
                e.json_idx = i

            for i, f in enumerate(obj.faces):
                f.json_idx = i

            obj_dict = dict()

            obj_dict["verts"] = self._create_dicts(
                obj, obj.verts, self.vertex_slots, self.vertex_attrs
            )

            obj_dict["edges"] = self._create_dicts(
                obj, obj.edges, self.edge_slots, self.edge_attrs
            )

            obj_dict["faces"] = self._create_dicts(
                obj, obj.faces, self.face_slots, self.face_attrs
            )

            return obj_dict
        return json.JSONEncoder.default(self, obj)

    @staticmethod
    def _create_dicts(surface, nodes, slots, attrs):
        nodes_dicts = []
        for v in nodes:
            node_dict = {}
            for slot in slots:
                node_dict[slot] = HalfedgeEncoder._get_index(surface, getattr(v, slot))
            for attr in attrs:
                node_attribute = getattr(nodes, attr)
                value = node_attribute[v]
                if isinstance(value, np.ndarray):
                    node_dict[attr] = tuple(value)
                else:
                    node_dict[attr] = value
            nodes_dicts.append(node_dict)
        return nodes_dicts

    @staticmethod
    def _get_index(surface, value):
        if isinstance(value, surface.verts):
            return value.json_idx
        if isinstance(value, surface.edges):
            return value.json_idx
        if isinstance(value, surface.faces):
            return value.json_idx
        if value is None:
            return -1
        return value


[docs]def to_json_string( surface, vertex_attrs=[], edge_attrs=[], face_attrs=[], write_index=False ): """ Create a json string from a given halfedge surface. Additional attributes to be included in the json string need to be specified explicitly in the respective dictionaries. All the references to vertices, edges, and faces are realized using integer indices. The None face corresponds to `-1` Parameters ---------- surface : halfedge surface The surface to be converted to a json string vertex_attrs : list of strings vertex attributes to be contained in the json string in addition to `edge` edge_attrs edge attributes to be contained in the json string in addition to `pre`, `nex`, `opp`, `head`, `face` face_attrs face attributes to be contained in the json string in addition to `edge` Returns ------- string """ if write_index: halfedge_encoder = HalfedgeEncoder( vertex_attrs + ["json_idx"], edge_attrs + ["json_idx"], face_attrs + ["json_idx"], ) else: halfedge_encoder = HalfedgeEncoder( vertex_attrs, edge_attrs, face_attrs, indent=2 ) return halfedge_encoder.encode(surface)
[docs]def to_json(surface, filename, vertex_attrs=[], edge_attrs=[], face_attrs=[]): """ Create a file in json format from a given halfedge surface. Additional attributes to be included in the json string need to be specified explicitly in the respective dictionaries. All the references to vertices, edges, and faces are realized using integer indices. The None face corresponds to `-1` Parameters ---------- surface : halfedge surface The surface to be converted to a json string filename : string file to be written vertex_attrs : list of strings vertex attributes to be contained in the json string in addition to `edge` edge_attrs edge attributes to be contained in the json string in addition to `pre`, `nex`, `opp`, `head`, `face` face_attrs face attributes to be contained in the json string in addition to `edge` """ with open(filename, "w") as outfile: outfile.write(to_json_string(surface, vertex_attrs, edge_attrs, face_attrs))
[docs]def from_json(filename): """ Create a surface from a json file. All keys will be mapped to respective attribute of the vertices, edges, and faces. Parameters ---------- filename: string file containing a json representing a halfedge surface Returns ------- surface Raises ------ ValueError If required attributes are missing in the json string """ with open(filename, "r") as f: d = json.load(f) _validate_surface_dict(d) return _dict_to_surf(d)
def parse_json_string(json_string): """ Create a surface from a json string. All keys will be mapped to respective attribute of the vertices, edges, and faces. Parameters ---------- json_string : string formatted string containing a halfedge surface Returns ------- surface Raises ------ ValueError If required attributes are missing in the json string """ json_dict = json.loads(json_string) _validate_surface_dict(json_dict) return _dict_to_surf(json_dict) def _validate_surface_dict(json_dict): _validate_node_dict(json_dict["verts"], ["edge"]) _validate_node_dict(json_dict["edges"], ["pre", "nex", "opp", "head", "face"]) _validate_node_dict(json_dict["faces"], ["edge"]) def _validate_node_dict(nodes, required_attributes): for n in nodes: missing_attributes = required_attributes - n.keys() if len(missing_attributes) > 0: raise ValueError( "Halfedge surface dictionary does not contain required attributes" f" {missing_attributes}." ) def _dict_to_surf(d): s = ddg.halfedge.Surface() vertices = _create_nodes_with_attributes(d, "verts", s.verts) edges = _create_nodes_with_attributes(d, "edges", s.edges) faces = _create_nodes_with_attributes(d, "faces", s.faces) _assign_node_attributes(zip(vertices, d["verts"]), s.verts, vertices, edges, faces) _assign_node_attributes(zip(edges, d["edges"]), s.edges, vertices, edges, faces) _assign_node_attributes(zip(faces, d["faces"]), s.faces, vertices, edges, faces) return s def _assign_node_attributes(pairs, nodes, vertices, edges, faces): for node, json_node in pairs: for k in json_node.keys(): if (k == "pre") or (k == "nex") or (k == "opp") or (k == "edge"): setattr(node, k, edges[json_node[k]]) elif k == "face": if json_node[k] < 0: node.face = None else: node.face = faces[json_node[k]] elif k == "head": node.head = vertices[json_node[k]] else: node_attribute = getattr(nodes, k) node_attribute[node] = ( json_node[k] if not isinstance(json_node[k], list) else np.array(json_node[k]) ) def _create_nodes_with_attributes(d, node_name, nodes): new_nodes = [nodes() for vd in d[node_name]] json_node = d[node_name][0] for attribute in json_node.keys(): if not hasattr(nodes, attribute): nodes.add_attribute(attribute) return new_nodes
[docs]def surface_to_ifs_json(surface, vertex_attrs=["co"]): encoder = SurfaceToIFSEncoder(vertex_attrs) return encoder.encode(surface)
class SurfaceToIFSEncoder(json.JSONEncoder): def __init__(self, vertex_attrs=["co"], **kwargs): super(SurfaceToIFSEncoder, self).__init__(**kwargs) self.vertex_attrs = vertex_attrs def default(self, surface): if isinstance(surface, ddg.halfedge.Surface): surface_dict = {} surface.verts.add_attribute("json_idx") for i, v in enumerate(surface.verts): v.json_idx = i surface_dict["faces"] = [] for f in surface.faces: vertex_index_list = tuple( [v.json_idx for v in ddg.halfedge._get.face_vertices(f)] ) surface_dict["faces"].append(vertex_index_list) if len(self.vertex_attrs) != 0: surface_dict["verts"] = [] for v in surface.verts: vertex_dict = {} for attribute in self.vertex_attrs: v_attribute = getattr(surface.verts, attribute) value = v_attribute[v] vertex_dict[attribute] = value.tolist() surface_dict["verts"].append(vertex_dict) return surface_dict return json.JSONEncoder.default(self, surface)