From dadcbd90d2e4576925566e00d6d1d5983303df4b Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 30 Jan 2025 10:21:10 -0500 Subject: [PATCH] Improve cone rendering plus some lint... Surface bottom added to cone; cone orientation corrected. --- mathics/builtin/drawing/graphics_internals.py | 2 +- mathics/format/asy.py | 56 +++++++++++-------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/mathics/builtin/drawing/graphics_internals.py b/mathics/builtin/drawing/graphics_internals.py index fdbba4c4b..adb5c27aa 100644 --- a/mathics/builtin/drawing/graphics_internals.py +++ b/mathics/builtin/drawing/graphics_internals.py @@ -26,7 +26,7 @@ def create_as_style(klass, graphics, item): class _GraphicsElementBox(BoxExpression, ABC): - def init(self, graphics, item=None, style=None, opacity=1.0): + def init(self, graphics, item=None, style={}, opacity=1.0): if item is not None and not item.has_form(self.get_name(), None): raise BoxExpressionError self.graphics = graphics diff --git a/mathics/format/asy.py b/mathics/format/asy.py index c055619c9..3fe41b44e 100644 --- a/mathics/format/asy.py +++ b/mathics/format/asy.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Lower-level format of Mathics objects as Asymptote strings. +Lower-level format of Mathics objects as Asymptote Vector graphics strings. """ import re @@ -36,10 +36,6 @@ PointSize, RGBColor, ) - -INVERSE_POINT_FACTOR = 1 / DEFAULT_POINT_FACTOR - - from mathics.core.formatter import add_conversion_fn, lookup_method from mathics.format.asy_fns import ( asy_add_bezier_fn, @@ -50,6 +46,8 @@ asy_number, ) +INVERSE_POINT_FACTOR = 1 / DEFAULT_POINT_FACTOR + class _ASYTransform: _template = """ @@ -97,7 +95,7 @@ def arcbox(self: _ArcBox, **options) -> str: # It is an empty circle return _roundbox(self) - x, y, rx, ry, sx, sy, ex, ey, large_arc = self._arc_params() + x, y, rx, ry, sx, sy, ex, ey, _ = self._arc_params() ry = max(ry, 0.1) # Avoid division by 0 yscale = ry / rx @@ -137,7 +135,7 @@ def create_arc_path(is_closed: bool, yscale: float) -> str: edge_opacity=edge_opacity_value, face_opacity=face_opacity_value, stroke_width=stroke_width, - is_face_element=self.face_element, + is_face_element=bool(self.face_element), ) command = "filldraw" if self.face_element else "draw" arc_path = create_arc_path(self.face_element or False, yscale) @@ -254,27 +252,34 @@ def cone3dbox(self: Cone3DBox, **options) -> str: opacity = self.face_opacity color_str = build_3d_pen_color(face_color, opacity) - # FIXME: currently always drawing around the axis X+Y - axes_point = (1, 1, 0) - asy = "// Cone3DBox\n" i = 0 while i < len(self.points) / 2: try: - point1 = self.points[i * 2].pos()[0] - point2 = self.points[i * 2 + 1].pos()[0] - - # Compute distance between start point and end point. - distance = ( - (point1[0] - point2[0]) ** 2 - + (point1[1] - point2[1]) ** 2 - + (point1[2] - point2[2]) ** 2 + # See https://tex.stackexchange.com/questions/736116/how-to-draw-the-base-geometrical-face-of-a-cone-surface-by-asymptote/736120#736120 + cone_center = self.points[i * 2].pos()[0] + cone_tip = self.points[i * 2 + 1].pos()[0] + if cone_center is None or cone_tip is None: + continue + + # Compute the distance between start point, the base point and the + # cone tip point. + cone_height = ( + (cone_center[0] - cone_tip[0]) ** 2 + + (cone_center[1] - cone_tip[1]) ** 2 + + (cone_center[2] - cone_tip[2]) ** 2 ) ** 0.5 - asy += ( - f"draw(surface(cone({tuple(point1)}, {self.radius}, {distance}, {axes_point})), {color_str});" - + "\n" - ) + asy += f""" + triple cone_center = {tuple(cone_center)}; + triple cone_tip = {tuple(cone_tip)}; + real cone_radius = {self.radius}; + real cone_height = {cone_height}; + + path3 cone_circle = circle(cone_center, cone_radius, cone_tip); + draw(surface(cone_circle), {color_str}); + draw(surface(cone(cone_center, cone_radius, cone_height, cone_tip)), {color_str}); + """ except: # noqa pass @@ -299,6 +304,9 @@ def cuboid3dbox(self: Cuboid3DBox, **options) -> str: point1 = self.points[i * 2].pos()[0] point2 = self.points[i * 2 + 1].pos()[0] + if point1 is None or point2 is None: + continue + asy += f""" draw(shift({point1[0]}, {point1[1]}, {point1[2]}) * scale( {point2[0] - point1[0]}, @@ -334,6 +342,10 @@ def cylinder3dbox(self: Cylinder3DBox, **options) -> str: try: point1 = self.points[i * 2].pos()[0] point2 = self.points[i * 2 + 1].pos()[0] + + if point1 is None or point2 is None: + continue + asy += f"real r={self.radius};\n" asy += f"triple A={tuple(point1)}, B={tuple(point2)};\n" asy += "real h=abs(A-B);\n"