diff --git a/mathics/builtin/drawing/graphics3d.py b/mathics/builtin/drawing/graphics3d.py
index 3f2c13a57..96ec52a61 100644
--- a/mathics/builtin/drawing/graphics3d.py
+++ b/mathics/builtin/drawing/graphics3d.py
@@ -195,20 +195,24 @@ class Sphere(Builtin):
class Cone(Builtin):
"""
- :WMA link:https://reference.wolfram.com/language/ref/Cone.html
+ :Cone:https://en.wikipedia.org/wiki/Cone (
+ :WMA:https://reference.wolfram.com/language/ref/Cone.html)
- - 'Cone'[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}}]
-
- represents a cone of radius 1.
+
- 'Cone'[]
+
- is a cone of radius 1 and height 2 oriented in the upward $z$ direction.
-
- 'Cone'[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}}, $r$]
-
- is a cone of radius $r$ starting at ($x1$, $y1$, $z1$) and ending at \
- ($x2$, $y2$, $z2$).
+
- 'Cone'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_2$}}, $r$]
+
- is a cone of radius $r$ starting at ($x_1$, $y_1$, $z_1$) and ending at \
+ ($x2$, $y_2$, $z_2$).
-
- 'Cone'[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}, ... }, $r$]
+
- 'Cone'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_2$}, ... }, $r$]
- is a collection cones of radius $r$.
+ >> Graphics3D[Cone[]]
+ = -Graphics3D-
+
>> Graphics3D[Cone[{{0, 0, 0}, {1, 1, 1}}, 1]]
= -Graphics3D-
@@ -223,7 +227,7 @@ class Cone(Builtin):
}
rules = {
- "Cone[]": "Cone[{{0, 0, 0}, {1, 1, 1}}, 1]",
+ "Cone[]": "Cone[{{0, 0, 0}, {0, 0, 2}}, 1]",
"Cone[positions_List]": "Cone[positions, 1]",
}
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..46eda1a70 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 cone's height : the distance between the center of the cone's base and the
+ # cone's tip.
+ 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"