Exemple #1
0
 def __init__(self, debug, cad_width, height):
     self.debug_output = Output()
     self.debug = debug
     self.cad_width = cad_width
     self.height = height
     self.display = CadqueryDisplay()
     widget = self.display.create(height=height, cad_width=cad_width)
     self.display.display(widget)
Exemple #2
0
def _show(assembly,
          height=600,
          tree_width=250,
          cad_width=800,
          quality=0.5,
          axes=False,
          axes0=True,
          grid=False,
          ortho=True,
          transparent=False,
          position=None,
          rotation=None,
          zoom=None,
          mac_scrollbar=True,
          sidecar=None):
    def sidecar_display(sidecar, widget):
        sidecar.clear_output(True)
        with sidecar:
            display(widget)
        print("Done, using side car '%s'" % sidecar.title)

    d = CadqueryDisplay()
    widget = d.display(states=assembly.to_state(),
                       shapes=assembly.collect_shapes(),
                       mapping=assembly.obj_mapping(),
                       tree=assembly.to_nav_dict(),
                       height=height,
                       tree_width=tree_width,
                       cad_width=cad_width,
                       quality=quality,
                       axes=axes,
                       axes0=axes0,
                       grid=grid,
                       ortho=ortho,
                       transparent=transparent,
                       position=position,
                       rotation=rotation,
                       zoom=zoom,
                       mac_scrollbar=mac_scrollbar)

    d.info.ready_msg(d.cq_view.grid.step)

    if sidecar is not None:
        if not sidecar:  # global sidecar setting overwritten by False
            display(widget)
        else:  # use provided sidecar
            sidecar_display(sidecar, widget)
    else:
        if SIDECAR is not None:  # use global sidecar
            sidecar_display(SIDECAR, widget)
        else:
            display(widget)
    return d
Exemple #3
0
 def __init__(self, quality, deviation, angular_tolerance, edge_accuracy,
              debug, cad_width, height):
     self.debug_output = Output()
     self.quality = quality
     self.deviation = deviation
     self.angular_tolerance = angular_tolerance
     self.edge_accuracy = edge_accuracy
     self.debug = debug
     self.cad_width = cad_width
     self.height = height
     self.display = CadqueryDisplay()
     widget = self.display.create(height=height, cad_width=cad_width)
     self.display.display(widget)
Exemple #4
0
def _show(assembly,
          height=600,
          tree_width=250,
          cad_width=800,
          quality=0.5,
          axes=False,
          axes0=True,
          grid=False,
          ortho=True,
          transparent=False,
          position=None,
          rotation=None,
          zoom=None,
          mac_scrollbar=True,
          sidecar=None):

    d = CadqueryDisplay()
    widget = d.create(states=assembly.to_state(),
                      shapes=assembly.collect_shapes(),
                      mapping=assembly.obj_mapping(),
                      tree=assembly.to_nav_dict(),
                      height=height,
                      tree_width=tree_width,
                      cad_width=cad_width,
                      quality=quality,
                      axes=axes,
                      axes0=axes0,
                      grid=grid,
                      ortho=ortho,
                      transparent=transparent,
                      position=position,
                      rotation=rotation,
                      zoom=zoom,
                      mac_scrollbar=mac_scrollbar)

    d.info.ready_msg(d.cq_view.grid.step)

    d.display(widget, sidecar)

    return d
Exemple #5
0
def _show(assembly, **kwargs):

    d = CadqueryDisplay()
    params = d.defaults.copy()
    for k, v in kwargs.items():
        if params.get(k, None) is None:
            raise KeyError("Paramater %s is not a valid argument for show()" % k)
        else:
            params[k] = v

    widget = d.create(
        states=assembly.to_state(),
        shapes=assembly.collect_shapes(),
        mapping=assembly.obj_mapping(),
        tree=assembly.to_nav_dict(),
        height=params["height"],
        tree_width=params["tree_width"],
        cad_width=params["cad_width"],
        quality=params["quality"],
        angular_tolerance=params["angular_tolerance"],
        edge_accuracy=params["edge_accuracy"],
        axes=params["axes"],
        axes0=params["axes0"],
        grid=params["grid"],
        ortho=params["ortho"],
        transparent=params["transparent"],
        position=params["position"],
        rotation=params["rotation"],
        zoom=params["zoom"],
        mac_scrollbar=params["mac_scrollbar"],
        timeit=params["timeit"],
    )

    d.info.ready_msg(d.cq_view.grid.step)

    d.display(widget, params["sidecar"])

    return d
Exemple #6
0
def _show(assembly, **kwargs):
    for k in kwargs:
        if get_default(k) is None:
            raise KeyError("Paramater %s is not a valid argument for show()" % k)

    mapping = assembly.to_state()
    shapes = assembly.collect_mapped_shapes(mapping)
    tree = tree = assembly.to_nav_dict()

    d = CadqueryDisplay()
    widget = d.create(**kwargs)
    d.display(widget)
    d.add_shapes(shapes=shapes, mapping=mapping, tree=tree)

    d.info.ready_msg(d.cq_view.grid.step)

    return d
Exemple #7
0
class Replay(object):
    def __init__(self, quality, deviation, angular_tolerance, edge_accuracy,
                 debug, cad_width, height):
        self.debug_output = Output()
        self.quality = quality
        self.deviation = deviation
        self.angular_tolerance = angular_tolerance
        self.edge_accuracy = edge_accuracy
        self.debug = debug
        self.cad_width = cad_width
        self.height = height
        self.display = CadqueryDisplay()
        widget = self.display.create(height=height, cad_width=cad_width)
        self.display.display(widget)

    def format_steps(self, raw_steps):
        def to_code(step, results):
            def to_name(obj):
                if isinstance(obj, cq.Workplane):
                    name = results.get(obj, None)
                else:
                    name = str(obj)
                return obj if name is None else name

            if step.func != "":
                if step.func == "newObject":
                    args = ("...", )
                else:
                    args = tuple([to_name(arg) for arg in step.args])
                code = "%s%s%s" % ("| " * step.level, step.func, args)
                code = code[:-2] if len(step.args) == 1 else code[:-1]
                if len(step.args) > 0 and len(step.kwargs) > 0:
                    code += ","
                if step.kwargs != {}:
                    code += ", ".join(
                        ["%s=%s" % (k, v) for k, v in step.kwargs.items()])
                code += ")"
                if step.result_name != "":
                    code += " => %s" % step.result_name
            elif step.var != "":
                code = "%s%s" % ("| " * step.level, step.var)
            else:
                code = "ERROR"
            return code

        steps = []
        entries = []
        obj_index = 1

        results = {step.result_obj: None for step in raw_steps}

        for i in range(len(raw_steps)):
            step = raw_steps[i]
            next_level = step.level if i == (len(raw_steps) -
                                             1) else raw_steps[i + 1].level

            # level change, so add/use the variable name
            if step.level > 0 and step.level != next_level and step.result_name == "":
                obj_name = "_v%d" % obj_index
                obj_index += 1
                step.result_name = obj_name
            steps.append(step)

        for step in steps:
            if results[step.result_obj] is None:
                # first occurence, take note and keep
                results[step.result_obj] = step.result_name
            else:
                # next occurences remove function and add variable name
                step.var = results[step.result_obj]
                step.clear_func()

        last_level = 1000000
        for step in reversed(steps):
            if step.level < last_level:
                last_level = 1000000
                entries.insert(0, (to_code(step, results), step.result_obj))
                if step.var != "":
                    last_level = step.level

        return entries

    def to_array(self, workplane, level=0, result_name=""):
        def walk(caller, level=0, result_name=""):
            stack = [
                Step(
                    level,
                    func=caller["func"],
                    args=caller["args"],
                    kwargs=caller["kwargs"],
                    result_name=result_name,
                    result_obj=caller["obj"],
                )
            ]
            for child in reversed(caller["children"]):
                stack = walk(child, level + 1) + stack
                for arg in child["args"]:
                    if isinstance(arg, cq.Workplane):
                        result_name = getattr(arg, "name", None)
                        stack = self.to_array(arg,
                                              level=level + 2,
                                              result_name=result_name) + stack
            return stack

        stack = []

        obj = workplane
        while obj is not None:
            caller = getattr(obj, "_caller", None)
            result_name = getattr(obj, "name", "")
            if caller is not None:
                stack = walk(caller, level, result_name) + stack
                for arg in caller["args"]:
                    if isinstance(arg, cq.Workplane):
                        result_name = getattr(arg, "name", "")
                        stack = self.to_array(arg,
                                              level=level + 1,
                                              result_name=result_name) + stack
            obj = obj.parent

        return stack

    def select_handler(self, change):
        with self.debug_output:
            if change["name"] == "index":
                self.select(change["new"])

    def select(self, indexes):
        self.debug_output.clear_output()
        with self.debug_output:
            self.indexes = indexes
            cad_objs = [self.stack[i][1] for i in self.indexes]

        # Add hidden result to start with final size and allow for comparison
        if not isinstance(self.stack[-1][1].val(), cq.Vector):
            result = Part(self.stack[-1][1],
                          "Result",
                          show_faces=False,
                          show_edges=False)
            objs = [result] + cad_objs
        else:
            objs = cad_objs

        with self.debug_output:
            assembly = to_assembly(*objs)
            mapping = assembly.to_state()
            shapes = assembly.collect_mapped_shapes(
                mapping,
                quality=self.quality,
                deviation=self.deviation,
                angular_tolerance=self.angular_tolerance,
                edge_accuracy=self.edge_accuracy,
                render_edges=get_default("render_edges"),
                render_normals=get_default("render_normals"),
            )
            tree = assembly.to_nav_dict()

            self.display.add_shapes(shapes=shapes,
                                    mapping=mapping,
                                    tree=tree,
                                    bb=_combined_bb(shapes),
                                    reset_camera=False)
Exemple #8
0
class Viewer:
    def __init__(self, zmq_port):
        self.zmq_port = zmq_port
        self.cad_display = None
        self.interactive = None
        self.zmq_server = None
        self.root_group = None
        self.log_output = widgets.Output(
            layout=widgets.Layout(height="400px", overflow="scroll"))
        self.log_output.add_class("mac-scrollbar")

    def _display(self, data, logo=False):
        mesh_data = data["data"]
        config = data["config"]
        info(mesh_data["bb"])

        if logo or config.get("cad_width") is None:
            config["cad_width"] = get_default("cad_width")
        else:
            if config.get("cad_width") < 640:
                warn("cad_width has to be >= 640, setting to 640")
                config["cad_width"] = 640

        if logo or config.get("height") is None:
            config["height"] = get_default("height")
        else:
            if config.get("height") < 400:
                warn("height has to be >= 400, setting to 400")
                config["height"] = 400

        if logo or config.get("tree_width") is not None:
            config["tree_width"] = get_default("tree_width")
        else:
            if config.get("tree_width") < 200:
                warn("tree_width has to be >= 200, setting to 200")
                config["tree_width"] = 200

        width = config["cad_width"] + config["tree_width"] + 6

        if self.interactive is not None:
            self.interactive.layout.width = px(width - 30)
        if self.log_output is not None:
            self.log_output.layout.width = px(width - 30)
        self.log_view.layout.width = px(width)

        # Force reset of camera to not inhereit splash settings for first object
        if self.cad_display.splash:
            config["reset_camera"] = True
            self.cad_display.splash = False

        self.cad_display.set_size(config.get("tree_width"),
                                  config.get("cad_width"),
                                  config.get("height"))
        self.cad_display.init_progress(data.get("count", 1))
        create_args, add_shape_args = split_args(config)
        self.cad_display._update_settings(**create_args)
        self.cad_display.add_shapes(**mesh_data, **add_shape_args)
        info(create_args, add_shape_args)
        self.cad_display.info.ready_msg(self.cad_display.cq_view.grid.step)
        self.root_group = self.cad_display.root_group

    def start_viewer(self, cad_width, cad_height, theme):
        info(f"zmq_port:   {self.zmq_port}")
        info(f"theme:      {theme}")
        info(f"cad_width:  {cad_width}")
        info(f"cad_height: {cad_height}")

        set_defaults(theme=theme, cad_width=cad_width, height=cad_height)

        self.interactive = widgets.Output(layout=widgets.Layout(height="0px"))

        self.cad_display = CadqueryDisplay()
        cad_view = self.cad_display.create()

        # remove jupyter cadquery start message
        clear_output()

        self.log_view = widgets.Accordion(children=[self.log_output])
        self.log_view.set_title(0, "Log")
        self.log_view.selected_index = None
        display(widgets.VBox([cad_view, self.interactive, self.log_view]))

        logo = pickle.loads(base64.b64decode(LOGO_DATA))
        self._display(logo, True)
        self.cad_display.splash = True

        stop_viewer()

        context = zmq.Context()
        socket = context.socket(zmq.REP)
        for i in range(5):
            try:
                socket.bind(f"tcp://*:{self.zmq_port}")
                break
            except Exception as ex:
                print(f"{ex}: retrying ... ")
                time.sleep(1)

        self.zmq_server = socket
        info("zmq started\n")

        def return_error(error_msg):
            error(error_msg)
            socket.send_json({"result": "error", "msg": error_msg})

        def return_success(t):
            info(f"duration: {time.time() - t:7.2f}")
            socket.send_json({"result": "success"})

        def msg_handler():
            while True:
                msg = socket.recv()
                try:
                    data = pickle.loads(msg)
                except Exception as ex:
                    return_error(str(ex))
                    continue

                self.interactive.outputs = ()
                self.interactive.layout.height = f"0px"

                if data.get("type") == "data":
                    try:
                        t = time.time()
                        self._display(data)
                        return_success(t)

                    except Exception as ex:
                        error_msg = f"{type(ex).__name__}: {ex}"
                        return_error(error_msg)

                elif data.get("type") == "animation":
                    try:
                        t = time.time()
                        animation = Animation(self.root_group)
                        for track in data["tracks"]:
                            animation.add_track(*track)
                        widget = animation.animate(data["speed"],
                                                   data["autoplay"])

                        # With INTERACTIVE: display(widget) does not work, see
                        # https://ipywidgets.readthedocs.io/en/7.6.3/examples/Output%20Widget.html#Interacting-with-output-widgets-from-background-threads
                        #
                        # INTERACTIVE.addpend_display_data(widget) doesn't work either, see https://github.com/jupyter-widgets/ipywidgets/issues/1811
                        # Should be solved, however isn't
                        #
                        mime_data = {
                            "output_type": "display_data",
                            "data": {
                                "text/plain": "AnimationAction",
                                "application/vnd.jupyter.widget-view+json": {
                                    "version_major": 2,
                                    "version_minor": 0,
                                    "model_id": widget.model_id,
                                },
                            },
                            "metadata": {},
                        }
                        self.interactive.outputs = (mime_data, )
                        self.interactive.layout.height = f"40px"
                        return_success(t)

                    except Exception as ex:
                        error_msg = f"{type(ex).__name__}: {ex}"
                        return_error(error_msg)
                else:
                    return_error(f"Wrong message type {data.get('type')}")

        thread = threading.Thread(target=msg_handler)
        thread.setDaemon(True)
        thread.start()
        self.cad_display.info.add_html("<b>zmq server started</b>")

    def stop_viewer(self):
        if self.zmq_server is not None:
            try:
                self.zmq_server.close()
                info("zmq stopped")
                if self.cad_display is not None and self.cad_display.info is not None:
                    self.cad_display.info.add_html("<b>HTTP zmq stopped</b>")
                self.zmq_server = None
                time.sleep(0.5)
            except Exception as ex:
                error("Exception %s" % ex)
Exemple #9
0
    def start_viewer(self, cad_width, cad_height, theme):
        info(f"zmq_port:   {self.zmq_port}")
        info(f"theme:      {theme}")
        info(f"cad_width:  {cad_width}")
        info(f"cad_height: {cad_height}")

        set_defaults(theme=theme, cad_width=cad_width, height=cad_height)

        self.interactive = widgets.Output(layout=widgets.Layout(height="0px"))

        self.cad_display = CadqueryDisplay()
        cad_view = self.cad_display.create()

        # remove jupyter cadquery start message
        clear_output()

        self.log_view = widgets.Accordion(children=[self.log_output])
        self.log_view.set_title(0, "Log")
        self.log_view.selected_index = None
        display(widgets.VBox([cad_view, self.interactive, self.log_view]))

        logo = pickle.loads(base64.b64decode(LOGO_DATA))
        self._display(logo, True)
        self.cad_display.splash = True

        stop_viewer()

        context = zmq.Context()
        socket = context.socket(zmq.REP)
        for i in range(5):
            try:
                socket.bind(f"tcp://*:{self.zmq_port}")
                break
            except Exception as ex:
                print(f"{ex}: retrying ... ")
                time.sleep(1)

        self.zmq_server = socket
        info("zmq started\n")

        def return_error(error_msg):
            error(error_msg)
            socket.send_json({"result": "error", "msg": error_msg})

        def return_success(t):
            info(f"duration: {time.time() - t:7.2f}")
            socket.send_json({"result": "success"})

        def msg_handler():
            while True:
                msg = socket.recv()
                try:
                    data = pickle.loads(msg)
                except Exception as ex:
                    return_error(str(ex))
                    continue

                self.interactive.outputs = ()
                self.interactive.layout.height = f"0px"

                if data.get("type") == "data":
                    try:
                        t = time.time()
                        self._display(data)
                        return_success(t)

                    except Exception as ex:
                        error_msg = f"{type(ex).__name__}: {ex}"
                        return_error(error_msg)

                elif data.get("type") == "animation":
                    try:
                        t = time.time()
                        animation = Animation(self.root_group)
                        for track in data["tracks"]:
                            animation.add_track(*track)
                        widget = animation.animate(data["speed"],
                                                   data["autoplay"])

                        # With INTERACTIVE: display(widget) does not work, see
                        # https://ipywidgets.readthedocs.io/en/7.6.3/examples/Output%20Widget.html#Interacting-with-output-widgets-from-background-threads
                        #
                        # INTERACTIVE.addpend_display_data(widget) doesn't work either, see https://github.com/jupyter-widgets/ipywidgets/issues/1811
                        # Should be solved, however isn't
                        #
                        mime_data = {
                            "output_type": "display_data",
                            "data": {
                                "text/plain": "AnimationAction",
                                "application/vnd.jupyter.widget-view+json": {
                                    "version_major": 2,
                                    "version_minor": 0,
                                    "model_id": widget.model_id,
                                },
                            },
                            "metadata": {},
                        }
                        self.interactive.outputs = (mime_data, )
                        self.interactive.layout.height = f"40px"
                        return_success(t)

                    except Exception as ex:
                        error_msg = f"{type(ex).__name__}: {ex}"
                        return_error(error_msg)
                else:
                    return_error(f"Wrong message type {data.get('type')}")

        thread = threading.Thread(target=msg_handler)
        thread.setDaemon(True)
        thread.start()
        self.cad_display.info.add_html("<b>zmq server started</b>")