def compute( self, shape, quality, angular_tolerance, tessellate=True, compute_edges=True, normals_len=0, debug=False, ): self.shape = shape self.normals_len = normals_len self.edges = [] count = self.number_solids(shape) with Timer(debug, "", f"mesh incrementally {'(parallel)' if count > 1 else ''}", 3): # Remove previous mesh data BRepTools.Clean_s(shape) BRepMesh_IncrementalMesh(shape, quality, False, angular_tolerance, count > 1) if tessellate: with Timer(debug, "", "get nodes, triangles and normals", 3): self.tessellate() if compute_edges: with Timer(debug, "", "get edges", 3): self.compute_edges()
def collect_shapes( self, loc, quality, deviation, angular_tolerance, edge_accuracy, render_edges, render_normals, progress=None, timeit=False, ): # A first rough estimate of the bounding box. # Will be too large, but is sufficient for computing the quality with Timer(timeit, self.name, "compute quality:", 2) as t: bb = bounding_box(self.shape, loc=loc, optimal=False) quality = compute_quality(bb, deviation=deviation) t.info = str(bb) normals_len = 0 if render_normals is False else quality / deviation * 5 with Timer(timeit, self.name, "tessellate: ", 2) as t: mesh = tessellate( self.shape, quality=quality, angular_tolerance=angular_tolerance, normals_len=normals_len, debug=timeit, compute_edges=render_edges, ) t.info = f"{{quality:{quality:.4f}, angular_tolerance:{angular_tolerance:.2f}}}" # After meshing the non optimal bounding box is much more exact with Timer(timeit, self.name, "bounding box: ", 2) as t: bb2 = bounding_box(self.shape, loc=loc, optimal=False) bb2.update(bb, minimize=True) t.info = str(bb2) if progress: progress.update() color = [c.web_color for c in self.color] if isinstance( self.color, tuple) else self.color.web_color return { "id": self.id, "type": "shapes", "name": self.name, "shape": mesh, "color": color, "bb": bb2.to_dict(), }
def collect_shapes( self, path, loc, deviation, angular_tolerance, edge_accuracy, render_edges, parallel=False, progress=None, timeit=False, ): self.id = f"{path}/{self.name}" with Timer(timeit, self.name, "bounding box:", 2) as t: bb = bounding_box(self.shape, loc=wrapped_or_None(loc)) quality = compute_quality(bb, deviation=deviation) deflection = quality / 100 if edge_accuracy is None else edge_accuracy t.info = str(bb) with Timer(timeit, self.name, "discretize: ", 2): edges = [] for edge in self.shape: edges.extend(discretize_edge(edge, deflection)) edges = np.asarray(edges) if progress: progress.update() color = [c.web_color for c in self.color] if isinstance( self.color, tuple) else self.color.web_color return { "id": self.id, "type": "edges", "name": self.name, "shape": edges, "color": color, "width": self.width, "bb": bb.to_dict(), }
def collect_shapes( self, loc, quality, deviation, angular_tolerance, edge_accuracy, render_edges, render_normals, progress=None, timeit=False, ): with Timer(timeit, self.name, "bounding box:", 2) as t: bb = bounding_box(self.shape, loc=loc) quality = compute_quality(bb, deviation=deviation) deflection = quality / 100 if edge_accuracy is None else edge_accuracy t.info = str(bb) with Timer(timeit, self.name, "discretize: ", 2): edges = flatten( [discretize_edge(edge, deflection) for edge in self.shape]) if progress: progress.update() color = [c.web_color for c in self.color] if isinstance( self.color, tuple) else self.color.web_color return { "id": self.id, "type": "edges", "name": self.name, "shape": edges, "color": color, "bb": bb, }
def _show(part_group, **kwargs): for k in kwargs: if get_default(k, "n/a") == "n/a": raise KeyError(f"Paramater {k} is not a valid argument for show()") if kwargs.get("cad_width") is not None and kwargs.get("cad_width") < 640: warn("cad_width has to be >= 640, setting to 640") kwargs["cad_width"] = 640 if kwargs.get("height") is not None and kwargs.get("height") < 400: warn("height has to be >= 400, setting to 400") kwargs["height"] = 400 if kwargs.get("tree_width") is not None and kwargs.get("tree_width") < 250: warn("tree_width has to be >= 250, setting to 250") kwargs["tree_width"] = 250 if kwargs.get("quality") is not None: warn( "quality is ignored. Use deviation to control smoothness of edges") del kwargs["quality"] sidecar_backup = None # if kwargs.get("parallel") is not None: # if kwargs["parallel"] and platform.system() != "Linux": # warn("parallel=True only works on Linux. Setting parallel=False") # kwargs["parallel"] = False timeit = preset("timeit", kwargs.get("timeit")) with Timer(timeit, "", "overall"): if part_group is None: import base64 # pylint:disable=import-outside-toplevel import pickle # pylint:disable=import-outside-toplevel from jupyter_cadquery.logo import LOGO_DATA # pylint:disable=import-outside-toplevel logo = pickle.loads(base64.b64decode(LOGO_DATA)) config = add_shape_args(logo["config"]) defaults = get_defaults() config["cad_width"] = defaults["cad_width"] config["tree_width"] = defaults["tree_width"] config["height"] = defaults["height"] config["glass"] = defaults["glass"] config["title"] = defaults["viewer"] for k, v in create_args(kwargs).items(): config[k] = v shapes = logo["data"]["shapes"] states = logo["data"]["states"] bb = _combined_bb(shapes).to_dict() # add global bounding box shapes["bb"] = bb else: config = apply_defaults(**kwargs) if config.get("viewer") == "": # If viewer is "" (the show default), then the default sidecar should be taken into account config["viewer"] = None elif config.get("viewer") is None: # if viewer is None (explicitely set), then ignore the default sidecar, i.e. back it up and set to None sidecar_backup = get_default_sidecar() _set_default_sidecar(None) if config.get("reset_camera") is False: # could be None if config.get("zoom") is not None: del config["zoom"] if config.get("position") is not None: del config["position"] if config.get("quaternion") is not None: del config["quaternion"] parallel = preset("parallel", config.get("parallel")) with Timer(timeit, "", "tessellate", 1): num_shapes = part_group.count_shapes() progress_len = 2 * num_shapes if parallel else num_shapes progress = None if num_shapes < 2 else Progress(progress_len) if parallel: init_pool() keymap.reset() shapes, states = _tessellate_group(part_group, tessellation_args(config), progress, timeit) if parallel: mp_get_results(shapes, progress) close_pool() bb = _combined_bb(shapes).to_dict() # add global bounding box shapes["bb"] = bb if progress is not None: progress.done() # Calculate normal length config["normal_len"] = get_normal_len( preset("render_normals", config.get("render_normals")), shapes, preset("deviation", config.get("deviation")), ) show_bbox = preset("show_bbox", kwargs.get("show_bbox")) if show_bbox: insert_bbox(show_bbox, shapes, states) with Timer(timeit, "", "show shapes", 1): cv = viewer_show(shapes, states, **show_args(config)) # If we forced to ignore the default sidecar, restore it if sidecar_backup is not None: _set_default_sidecar(sidecar_backup) return cv
def collect_shapes( self, path, loc, deviation, angular_tolerance, edge_accuracy, render_edges, parallel=False, progress=None, timeit=False, ): self.id = f"{path}/{self.name}" # A first rough estimate of the bounding box. # Will be too large, but is sufficient for computing the quality with Timer(timeit, self.name, "compute quality:", 2) as t: bb = bounding_box(self.shape, loc=wrapped_or_None(loc), optimal=False) quality = compute_quality(bb, deviation=deviation) t.info = str(bb) with Timer(timeit, self.name, "tessellate: ", 2) as t: func = mp_tessellate if parallel else tessellate result = func( self.shape, loc_to_tq(wrapped_or_None(loc)), deviation=deviation, quality=quality, angular_tolerance=angular_tolerance, debug=timeit, compute_edges=render_edges, ) t.info = f"{{quality:{quality:.4f}, angular_tolerance:{angular_tolerance:.2f}}}" if parallel and is_apply_result(result): mesh = result bb = {} else: mesh, bb = result if progress is not None: progress.update() if isinstance(self.color, tuple): color = [c.web_color for c in self.color] # pylint: disable=not-an-iterable else: color = self.color.web_color return { "id": self.id, "type": "shapes", "name": self.name, "shape": mesh, "color": color, "renderback": self.renderback, "accuracy": quality, "bb": bb, }
def _show(part_group, **kwargs): for k in kwargs: if get_default(k, "n/a") == "n/a": raise KeyError(f"Paramater {k} is not a valid argument for show()") if kwargs.get("cad_width") is not None and kwargs.get("cad_width") < 640: warn("cad_width has to be >= 640, setting to 640") kwargs["cad_width"] = 640 if kwargs.get("height") is not None and kwargs.get("height") < 400: warn("height has to be >= 400, setting to 400") kwargs["height"] = 400 if kwargs.get("tree_width") is not None and kwargs.get("tree_width") < 250: warn("tree_width has to be >= 250, setting to 250") kwargs["tree_width"] = 250 # remove all tessellation and view parameters create_args, add_shape_args = split_args(kwargs) preset = lambda key, value: get_default(key) if value is None else value timeit = preset("timeit", kwargs.get("timeit")) with Timer(timeit, "", "overall"): with Timer(timeit, "", "setup display", 1): num_shapes = part_group.count_shapes() d = get_or_create_display(**create_args) d.init_progress(2 * num_shapes) with Timer(timeit, "", "tessellate", 1): mapping = part_group.to_state() shapes = part_group.collect_mapped_shapes( mapping, quality=preset("quality", kwargs.get("quality")), deviation=preset("deviation", kwargs.get("deviation")), angular_tolerance=preset("angular_tolerance", kwargs.get("angular_tolerance")), edge_accuracy=preset("edge_accuracy", kwargs.get("edge_accuracy")), render_edges=preset("render_edges", kwargs.get("render_edges")), render_normals=preset("render_normals", kwargs.get("render_normals")), progress=d.progress, timeit=timeit, ) tree = part_group.to_nav_dict() with Timer(timeit, "", "show shapes", 1): d.add_shapes(shapes=shapes, mapping=mapping, tree=tree, bb=_combined_bb(shapes), **add_shape_args) d.info.version_msg(__version__) d.info.ready_msg(d.cq_view.grid.step) sidecar = has_sidecar() if sidecar is not None: print(f"Done, using side car '{sidecar.title()}'") return d