def path(closed): if closed: yield "(%s,%s)--(%s,%s)--" % tuple( asy_number(t) for t in (x, y, sx, sy)) yield "arc((%s,%s), (%s, %s), (%s, %s))" % tuple( asy_number(t) for t in (x, y, sx, sy, ex, ey)) if closed: yield "--cycle"
def _roundbox(self, **options): x, y = self.c.pos() rx, ry = self.r.pos() rx -= x ry -= y line_width = self.style.get_line_width(face_element=self.face_element) pen = asy_create_pens( edge_color=self.edge_color, face_color=self.face_color, stroke_width=line_width, is_face_element=self.face_element, ) cmd = "filldraw" if self.face_element else "draw" return "%s(ellipse((%s,%s),%s,%s), %s);" % ( cmd, asy_number(x), asy_number(y), asy_number(rx), asy_number(ry), pen, )
def boxes_to_tex(self, leaves=None, **options) -> str: if not leaves: leaves = self._leaves fields = self._prepare_elements(leaves, options, max_width=450) if len(fields) == 2: elements, calc_dimensions = fields else: elements, calc_dimensions = fields[0], fields[-2] fields = calc_dimensions() if len(fields) == 8: xmin, xmax, ymin, ymax, w, h, width, height = fields elements.view_width = w else: assert len(fields) == 9 xmin, xmax, ymin, ymax, _, _, _, width, height = fields elements.view_width = width asy_completely_visible = "\n".join( lookup_method(element, "asy")(element) for element in elements.elements if element.is_completely_visible) asy_regular = "\n".join( lookup_method(element, "asy")(element) for element in elements.elements if not element.is_completely_visible) asy_box = "box((%s,%s), (%s,%s))" % ( asy_number(xmin), asy_number(ymin), asy_number(xmax), asy_number(ymax), ) if self.background_color is not None: color, opacity = asy_color(self.background_color) asy_background = "filldraw(%s, %s);" % (asy_box, color) else: asy_background = "" tex = r""" \begin{asy} usepackage("amsmath"); size(%scm, %scm); %s %s clip(%s); %s \end{asy} """ % ( asy_number(width / 60), asy_number(height / 60), asy_background, asy_regular, asy_box, asy_completely_visible, ) return tex
def rectanglebox(self, **options) -> str: line_width = self.style.get_line_width(face_element=True) x1, y1 = self.p1.pos() x2, y2 = self.p2.pos() pens = asy_create_pens( self.edge_color, self.face_color, line_width, is_face_element=True ) x1, x2, y1, y2 = asy_number(x1), asy_number(x2), asy_number(y1), asy_number(y2) asy = "// RectangleBox\n" asy += "filldraw((%s,%s)--(%s,%s)--(%s,%s)--(%s,%s)--cycle, %s);" % ( x1, y1, x2, y1, x2, y2, x1, y2, pens, ) # print("### rectanglebox", asy) return asy
def create_arc_path(is_closed: bool, yscale: float) -> str: """Constructs arc path taking into account whether the path is closed and the scaling along the Y dimension (i.e. Mathics disks support ellipses. An Asymptote string for the path is returned. """ arc_path = "" if is_closed: arc_path = "(%s,%s)--(%s,%s)--" % tuple( asy_number(t) for t in (x, y, sx, sy) ) arc_path += "arc((%s,%s), (%s, %s), (%s, %s))" % tuple( asy_number(t) for t in (x, y, sx, sy, ex, ey) ) if is_closed: arc_path += "--cycle" if yscale != 1.0: arc_path = f"yscale({yscale}) * ({arc_path})" return arc_path
def boxes_to_tex(self, leaves=None, **options) -> str: """This is the top-level function that converts a Mathics Expression in to something suitable for LaTeX. (Yes, the name "tex" is perhaps misleading of vague.) However right now the only LaTeX support for graphics is via Asymptote and that seems to be the package of choice in general for LaTeX. """ if not leaves: leaves = self._leaves fields = self._prepare_elements(leaves, options, max_width=450) if len(fields) == 2: elements, calc_dimensions = fields else: elements, calc_dimensions = fields[0], fields[-2] fields = calc_dimensions() if len(fields) == 8: xmin, xmax, ymin, ymax, w, h, width, height = fields elements.view_width = w else: assert len(fields) == 9 xmin, xmax, ymin, ymax, _, _, _, width, height = fields elements.view_width = width asy_completely_visible = "\n".join( lookup_method(element, "asy")(element) for element in elements.elements if element.is_completely_visible) asy_regular = "\n".join( lookup_method(element, "asy")(element) for element in elements.elements if not element.is_completely_visible) asy_box = "box((%s,%s), (%s,%s))" % ( asy_number(xmin), asy_number(ymin), asy_number(xmax), asy_number(ymax), ) if self.background_color is not None: color, opacity = asy_color(self.background_color) asy_background = "filldraw(%s, %s);" % (asy_box, color) else: asy_background = "" tex = r""" \begin{asy} usepackage("amsmath"); size(%scm, %scm); %s %s clip(%s); %s \end{asy} """ % ( asy_number(width / 60), asy_number(height / 60), asy_background, asy_regular, asy_box, asy_completely_visible, ) return tex
def boxes_to_tex(self, leaves=None, **options): if not leaves: leaves = self._leaves ( elements, axes, ticks, ticks_style, calc_dimensions, boxscale, ) = self._prepare_elements(leaves, options, max_width=450) elements._apply_boxscaling(boxscale) format_fn = lookup_method(elements, "asy") if format_fn is not None: asy = format_fn(elements) else: asy = elements.to_asy() xmin, xmax, ymin, ymax, zmin, zmax, boxscale, w, h = calc_dimensions() # TODO: Intelligently place the axes on the longest non-middle edge. # See algorithm used by web graphics in mathics/web/media/graphics.js # for details of this. (Projection to sceen etc). # Choose axes placement (boundbox edge vertices) axes_indices = [] if axes[0]: axes_indices.append(0) if axes[1]: axes_indices.append(6) if axes[2]: axes_indices.append(8) # Draw boundbox and axes boundbox_asy = "" boundbox_lines = self.get_boundbox_lines(xmin, xmax, ymin, ymax, zmin, zmax) for i, line in enumerate(boundbox_lines): if i in axes_indices: pen = asy_create_pens(edge_color=RGBColor(components=(0, 0, 0, 1)), stroke_width=1.5) else: pen = asy_create_pens(edge_color=RGBColor(components=(0.4, 0.4, 0.4, 1)), stroke_width=1) path = "--".join(["(%.5g,%.5g,%.5g)" % coords for coords in line]) boundbox_asy += "draw((%s), %s);\n" % (path, pen) # TODO: Intelligently draw the axis ticks such that they are always # directed inward and choose the coordinate direction which makes the # ticks the longest. Again, details in mathics/web/media/graphics.js # Draw axes ticks ticklength = 0.05 * max([xmax - xmin, ymax - ymin, zmax - zmin]) pen = asy_create_pens(edge_color=RGBColor(components=(0, 0, 0, 1)), stroke_width=1.2) for xi in axes_indices: if xi < 4: # x axis for i, tick in enumerate(ticks[0][0]): line = [ (tick, boundbox_lines[xi][0][1], boundbox_lines[xi][0][2]), ( tick, boundbox_lines[xi][0][1], boundbox_lines[xi][0][2] + ticklength, ), ] path = "--".join( ["({0},{1},{2})".format(*coords) for coords in line]) boundbox_asy += "draw(({0}), {1});\n".format(path, pen) boundbox_asy += 'label("{0}",{1},{2});\n'.format( ticks[0][2][i], (tick, boundbox_lines[xi][0][1], boundbox_lines[xi][0][2]), "S", ) for small_tick in ticks[0][1]: line = [ ( small_tick, boundbox_lines[xi][0][1], boundbox_lines[xi][0][2], ), ( small_tick, boundbox_lines[xi][0][1], boundbox_lines[xi][0][2] + 0.5 * ticklength, ), ] path = "--".join( ["({0},{1},{2})".format(*coords) for coords in line]) boundbox_asy += "draw(({0}), {1});\n".format(path, pen) if 4 <= xi < 8: # y axis for i, tick in enumerate(ticks[1][0]): line = [ (boundbox_lines[xi][0][0], tick, boundbox_lines[xi][0][2]), ( boundbox_lines[xi][0][0], tick, boundbox_lines[xi][0][2] - ticklength, ), ] path = "--".join( ["({0},{1},{2})".format(*coords) for coords in line]) boundbox_asy += "draw(({0}), {1});\n".format(path, pen) boundbox_asy += 'label("{0}",{1},{2});\n'.format( ticks[1][2][i], (boundbox_lines[xi][0][0], tick, boundbox_lines[xi][0][2]), "NW", ) for small_tick in ticks[1][1]: line = [ ( boundbox_lines[xi][0][0], small_tick, boundbox_lines[xi][0][2], ), ( boundbox_lines[xi][0][0], small_tick, boundbox_lines[xi][0][2] - 0.5 * ticklength, ), ] path = "--".join( ["({0},{1},{2})".format(*coords) for coords in line]) boundbox_asy += "draw(({0}), {1});\n".format(path, pen) if 8 <= xi: # z axis for i, tick in enumerate(ticks[2][0]): line = [ (boundbox_lines[xi][0][0], boundbox_lines[xi][0][1], tick), ( boundbox_lines[xi][0][0], boundbox_lines[xi][0][1] + ticklength, tick, ), ] path = "--".join( ["({0},{1},{2})".format(*coords) for coords in line]) boundbox_asy += "draw(({0}), {1});\n".format(path, pen) boundbox_asy += 'label("{0}",{1},{2});\n'.format( ticks[2][2][i], (boundbox_lines[xi][0][0], boundbox_lines[xi][0][1], tick), "W", ) for small_tick in ticks[2][1]: line = [ ( boundbox_lines[xi][0][0], boundbox_lines[xi][0][1], small_tick, ), ( boundbox_lines[xi][0][0], boundbox_lines[xi][0][1] + 0.5 * ticklength, small_tick, ), ] path = "--".join( ["({0},{1},{2})".format(*coords) for coords in line]) boundbox_asy += "draw(({0}), {1});\n".format(path, pen) (height, width) = (400, 400) # TODO: Proper size tex = r""" \begin{{asy}} import three; import solids; size({0}cm, {1}cm); currentprojection=perspective({2[0]},{2[1]},{2[2]}); currentlight=light(rgb(0.5,0.5,1), specular=red, (2,0,2), (2,2,2), (0,2,2)); {3} {4} \end{{asy}} """.format( asy_number(width / 60), asy_number(height / 60), self.viewpoint, asy, boundbox_asy, ) return tex