Ticket #12083: trac12083_rebased_5.12.patch

File trac12083_rebased_5.12.patch, 28.0 KB (added by chapoton, 9 years ago)
  • sage/geometry/polyhedron/plot.py

    # HG changeset patch
    # User Jean-Philippe Labbé <labbe at math.fu-berlin.de>
    # Date 1355927867 -3600
    # Node ID 596081ebee8a284849c67835b49e1b867863b9dc
    # Parent  94d199f105440e37aa019c7d8be95ae0463bb698
    trac #12083: new tikz method to visualize polytopes, rebased to 5.13.beta1
    
    diff --git a/sage/geometry/polyhedron/plot.py b/sage/geometry/polyhedron/plot.py
    a b Functions for plotting polyhedra 
    1212########################################################################
    1313
    1414
    15 from sage.rings.all import QQ, ZZ, RDF
     15from sage.rings.all import RDF
    1616from sage.structure.sage_object import SageObject
    1717from sage.modules.free_module_element import vector
    1818from sage.matrix.constructor import matrix, identity_matrix
    1919from sage.misc.functional import norm
     20from sage.misc.latex import LatexExpr
     21from sage.symbolic.constants import pi
    2022from sage.structure.sequence import Sequence
    2123
    2224from sage.plot.all import point2d, line2d, arrow, polygon2d
    2325from sage.plot.plot3d.all import point3d, line3d, arrow3d, polygon3d
    24 from sage.graphs.graph import Graph
     26from sage.plot.plot3d.transform import rotate_arbitrary
    2527
    2628from base import is_Polyhedron
    27 from constructor import Polyhedron
    2829
    2930
    3031
    def render_3d(projection, point_opts={}, 
    7475    Return 3d rendering of a polyhedron projected into
    7576    3-dimensional ambient space.
    7677
    77     NOTE:
     78    .. NOTE::
    7879
    79     This method, ``render_3d``, is used in the ``show()``
    80     method of a polyhedron if it is in 3 dimensions.
     80        This method, ``render_3d``, is used in the ``show()``
     81        method of a polyhedron if it is in 3 dimensions.
    8182
    8283    EXAMPLES::
    8384
    def render_4d(polyhedron, point_opts={}, 
    116117    Return a 3d rendering of the Schlegel projection of a 4d
    117118    polyhedron projected into 3-dimensional space.
    118119
    119     NOTES:
     120    .. NOTE::
    120121
    121     The ``show()`` method of ``Polyhedron()`` uses this to draw itself
    122     if the ambient dimension is 4.
     122        The ``show()`` method of ``Polyhedron()`` uses this to draw itself
     123        if the ambient dimension is 4.
    123124
    124125    INPUT:
    125126
    def cyclic_sort_vertices_2d(Vlist): 
    170171    """
    171172    Return the vertices/rays in cyclic order if possible.
    172173
    173     NOTES:
     174    .. NOTE::
    174175
    175     This works if and only if each vertex/ray is adjacent to exactly
    176     two others. For example, any 2-dimensional polyhedron satisfies
    177     this.
     176        This works if and only if each vertex/ray is adjacent to exactly
     177        two others. For example, any 2-dimensional polyhedron satisfies
     178        this.
    178179
    179180    See
    180181    :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.vertex_adjacency_matrix`
    class Projection(SageObject): 
    447448
    448449        INPUT:
    449450
    450           - ``polyhedron`` -- a ``Polyhedron()`` object
     451        - ``polyhedron`` -- a ``Polyhedron()`` object
    451452
    452           - ``proj`` -- a projection function for the points
     453        - ``proj`` -- a projection function for the points
    453454
    454         NOTES:
     455        .. NOTE::
    455456
    456         Once initialized, the polyhedral data is fixed. However, the
    457         projection can be changed later on.
     457            Once initialized, the polyhedral data is fixed. However, the
     458            projection can be changed later on.
    458459
    459460        EXAMPLES::
    460461
    class Projection(SageObject): 
    474475            sage: proj.show()
    475476            sage: TestSuite(proj).run(skip='_test_pickling')
    476477        """
     478        self.parent_polyhedron = polyhedron
    477479        self.coords = Sequence([])
    478480        self.points = Sequence([])
    479481        self.lines  = Sequence([])
    class Projection(SageObject): 
    585587
    586588        INPUT:
    587589
    588           - ``projection_direction`` - The direction of the Schlegel
    589             projection. By default, the vector consisting of the first
    590             n primes is chosen.
     590        - ``projection_direction`` - The direction of the Schlegel
     591          projection. By default, the vector consisting of the first n
     592          primes is chosen.
    591593
    592594        EXAMPLES::
    593595
    class Projection(SageObject): 
    601603
    602604            sage: Projection(cube4).schlegel()
    603605            The projection of a polyhedron into 3 dimensions
     606
    604607        """
    605608        if projection_direction == None:
    606609            for poly in self.polygons:
    class Projection(SageObject): 
    872875                    yield ineq
    873876
    874877        faces = []
     878        face_inequalities = []
    875879        for facet_equation in defining_equation():
    876880            vertices = [v for v in facet_equation.incident()]
     881            face_inequalities.append(facet_equation)
    877882            vertices = cyclic_sort_vertices_2d(vertices)
    878883            coords = []
    879884
    class Projection(SageObject): 
    891896                        coords.append(a() + v())
    892897
    893898            faces.append(coords)
     899        self.face_inequalities = face_inequalities
    894900
    895901        if polyhedron.n_lines() == 0:
    896902            assert len(faces)>0, "no vertices?"
    class Projection(SageObject): 
    10231029        """
    10241030        return sum([ polygon3d(self.coordinates_of(f), **kwds)
    10251031                     for f in self.polygons ])
     1032
     1033    def tikz(self, view=[0,0,1], angle=0, scale=2,
     1034             edge_color='blue!95!black', facet_color='blue!95!black',
     1035             opacity=0.8, vertex_color='green', axis=False):
     1036        r"""
     1037        Return a string ``tikz_pic`` consisting of a tikz picture of ``self``
     1038        according to a projection ``view`` and an angle ``angle``
     1039        obtained via Jmol through the current state property.
     1040
     1041        INPUT:
     1042
     1043        - ``view`` - list (default: [0,0,1]) representing the rotation axis (see note below).
     1044        - ``angle`` - integer (default: 0) angle of rotation in degree from 0 to 360 (see note
     1045          below).
     1046        - ``scale`` - integer (default: 2) specifying the scaling of the tikz picture.
     1047        - ``edge_color`` - string (default: 'blue!95!black') representing colors which tikz
     1048          recognize.
     1049        - ``facet_color`` - string (default: 'blue!95!black') representing colors which tikz
     1050          recognize.
     1051        - ``vertex_color`` - string (default: 'green') representing colors which tikz
     1052          recognize.
     1053        - ``opacity`` - real number (default: 0.8) between 0 and 1 giving the opacity of
     1054          the front facets.
     1055        - ``axis`` - Boolean (default: False) draw the axes at the origin or not.
     1056
     1057        OUTPUT:
     1058
     1059        - LatexExpr -- containing the TikZ picture.
     1060
     1061        .. NOTE::
     1062
     1063            The inputs ``view`` and ``angle`` can be obtained from the
     1064            viewer Jmol::
     1065
     1066                1) Right click on the image
     1067                2) Select ``Console``
     1068                3) Select the tab ``State``
     1069                4) Scroll to the line ``moveto``
     1070
     1071            It reads something like::
     1072
     1073                moveto 0.0 {x y z angle} Scale
     1074
     1075            The ``view`` is then [x,y,z] and ``angle`` is angle.
     1076            The following number is the scale.
     1077
     1078            Jmol performs a rotation of ``angle`` degrees along the
     1079            vector [x,y,z] and show the result from the z-axis.
     1080
     1081        EXAMPLES::
     1082
     1083            sage: P1 = polytopes.small_rhombicuboctahedron()
     1084            sage: Image1 = P1.projection().tikz([1,3,5], 175, scale=4)
     1085            sage: type(Image1)
     1086            <class 'sage.misc.latex.LatexExpr'>
     1087            sage: print '\n'.join(Image1.splitlines()[:4])
     1088            \begin{tikzpicture}%
     1089                [x={(-0.939161cm, 0.244762cm)},
     1090                y={(0.097442cm, -0.482887cm)},
     1091                z={(0.329367cm, 0.840780cm)},
     1092            sage: open('polytope-tikz1.tex', 'w').write(Image1)    # not tested
     1093
     1094            sage: P2 = Polyhedron(vertices=[[1, 1],[1, 2],[2, 1]])
     1095            sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', facet_color='orange!95!black', opacity=0.4, vertex_color='yellow', axis=True)
     1096            sage: type(Image2)
     1097            <class 'sage.misc.latex.LatexExpr'>
     1098            sage: print '\n'.join(Image2.splitlines()[:4])
     1099            \begin{tikzpicture}%
     1100                [scale=3.000000,
     1101                back/.style={loosely dotted, thin},
     1102                edge/.style={color=blue!95!black, thick},
     1103            sage: open('polytope-tikz2.tex', 'w').write(Image2)    # not tested
     1104
     1105            sage: P3 = Polyhedron(vertices=[[-1, -1, 2],[-1, 2, -1],[2, -1, -1]])
     1106            sage: P3
     1107            A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
     1108            sage: Image3 = P3.projection().tikz([0.5,-1,-0.1], 55, scale=3, edge_color='blue!95!black',facet_color='orange!95!black', opacity=0.7, vertex_color='yellow', axis=True)
     1109            sage: print '\n'.join(Image3.splitlines()[:4])
     1110            \begin{tikzpicture}%
     1111                [x={(0.658184cm, -0.242192cm)},
     1112                y={(-0.096240cm, 0.912008cm)},
     1113                z={(-0.746680cm, -0.331036cm)},
     1114            sage: open('polytope-tikz3.tex', 'w').write(Image3)    # not tested
     1115
     1116            sage: P=Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]])
     1117            sage: P
     1118            A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices
     1119            sage: P.projection().tikz()
     1120            Traceback (most recent call last):
     1121            ...
     1122            NotImplementedError: The polytope has to live in 2 or 3 dimensions.
     1123
     1124        .. TODO::
     1125
     1126            Make it possible to draw Schlegel diagram for 4-polytopes. ::
     1127
     1128                sage: P=Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]])
     1129                sage: P
     1130                A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices
     1131                sage: P.projection().tikz()
     1132                Traceback (most recent call last):
     1133                ...
     1134                NotImplementedError: The polytope has to live in 2 or 3 dimensions.
     1135
     1136            Make it possible to draw 3-polytopes living in higher dimension.
     1137        """
     1138        if self.polyhedron_ambient_dim > 3 or self.polyhedron_ambient_dim < 2:
     1139            raise NotImplementedError("The polytope has to live in 2 or 3 dimensions.")
     1140        elif self.polyhedron_ambient_dim == 2:
     1141            return self._tikz_2d(scale, edge_color, facet_color, opacity,
     1142                                 vertex_color, axis)
     1143        elif self.dimension == 2:
     1144            return self._tikz_2d_in_3d(view, angle, scale, edge_color,
     1145                                       facet_color, opacity, vertex_color, axis)
     1146        else:
     1147            return self._tikz_3d_in_3d(view, angle, scale, edge_color,
     1148                                       facet_color, opacity, vertex_color, axis)
     1149
     1150    def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis):
     1151        r"""
     1152        Return a string ``tikz_pic`` consisting of a tikz picture of ``self``
     1153
     1154        INPUT:
     1155
     1156        - ``scale`` - integer specifying the scaling of the tikz picture.
     1157        - ``edge_color`` - string representing colors which tikz
     1158          recognize.
     1159        - ``facet_color`` - string representing colors which tikz
     1160          recognize.
     1161        - ``vertex_color`` - string representing colors which tikz
     1162          recognize.
     1163        - ``opacity`` - real number between 0 and 1 giving the opacity of
     1164          the front facets.
     1165        - ``axis`` - Boolean (default: False) draw the axes at the origin or not.
     1166
     1167        OUTPUT:
     1168
     1169        - LatexExpr -- containing the TikZ picture.
     1170
     1171        EXAMPLES::
     1172
     1173            sage: P = Polyhedron(vertices=[[1, 1],[1, 2],[2, 1]])
     1174            sage: Image = P.projection()._tikz_2d(scale=3, edge_color='black', facet_color='orange', opacity=0.75, vertex_color='yellow', axis=True)
     1175            sage: type(Image)
     1176            <class 'sage.misc.latex.LatexExpr'>
     1177            sage: print '\n'.join(Image.splitlines()[:4])
     1178            \begin{tikzpicture}%
     1179                [scale=3.000000,
     1180                back/.style={loosely dotted, thin},
     1181                edge/.style={color=black, thick},
     1182            sage: open('polytope-tikz2.tex', 'w').write(Image)    # not tested
     1183
     1184        .. NOTE::
     1185
     1186            The ``facet_color`` is the filing color of the polytope (polygon).
     1187        """
     1188
     1189        # Creates the nodes, coordinate and tag for every vertex of the polytope.
     1190        # The tag is used to draw the front facets later on.
     1191
     1192        dict_drawing = {}
     1193        edges = ''
     1194        for vert in self.points:
     1195            v = self.coords[vert]
     1196            v_vect = str([i.n(digits=3) for i in v])
     1197            v_vect = v_vect.replace('[', '(')
     1198            v_vect = v_vect.replace(']', ')')
     1199            tag = '%s' %v_vect
     1200            node = "\\node[%s] at %s     {};\n" % ('vertex', tag)
     1201            coord = '\coordinate %s at %s;\n' % (tag, tag)
     1202            dict_drawing[vert] = node, coord, tag
     1203
     1204        for index1, index2 in self.lines:
     1205            # v1 = self.coords[index1]
     1206            # v2 = self.coords[index2]
     1207            edges += "\\draw[%s] %s -- %s;\n" % ('edge',
     1208                                                 dict_drawing[index1][2],
     1209                                                 dict_drawing[index2][2])
     1210
     1211        # Start to write the output
     1212        tikz_pic = ''
     1213        tikz_pic += '\\begin{tikzpicture}%\n'
     1214        tikz_pic += '\t[scale=%f,\n' % scale
     1215        tikz_pic += '\tback/.style={loosely dotted, thin},\n'
     1216        tikz_pic += '\tedge/.style={color=%s, thick},\n' % edge_color
     1217        tikz_pic += '\tfacet/.style={fill=%s,fill opacity=%f},\n' % (facet_color,opacity)
     1218        tikz_pic += '\tvertex/.style={inner sep=1pt,circle,draw=%s!25!black,' % vertex_color
     1219        tikz_pic += 'fill=%s!75!black,thick,anchor=base}]\n%%\n%%\n' % vertex_color
     1220
     1221        # Draws the axes if True
     1222        if axis:
     1223            tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$};\n'
     1224            tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$};\n'
     1225
     1226        # Create the coordinate of the vertices:
     1227        tikz_pic += '%% Coordinate of the vertices:\n%%\n'
     1228        for v in dict_drawing:
     1229            tikz_pic += dict_drawing[v][1]
     1230
     1231        # Draw the interior by going in a cycle
     1232        vertices = list(self.parent_polyhedron.Vrep_generator())
     1233        tikz_pic += '%%\n%%\n%% Drawing the interior\n%%\n'
     1234        cyclic_vert = cyclic_sort_vertices_2d(list(self.parent_polyhedron.Vrep_generator()))
     1235        cyclic_indices = [vertices.index(v) for v in cyclic_vert]
     1236        tikz_pic += '\\fill[facet] '
     1237        for v in cyclic_indices:
     1238            if v in dict_drawing:
     1239                tikz_pic += '%s -- ' % dict_drawing[v][2]
     1240        tikz_pic += 'cycle {};\n'
     1241
     1242        # Draw the edges
     1243        tikz_pic += '%%\n%%\n%% Drawing edges\n%%\n'
     1244        tikz_pic += edges
     1245
     1246        # Finally, the vertices in front are drawn on top of everything.
     1247        tikz_pic += '%%\n%%\n%% Drawing the vertices\n%%\n'
     1248        for v in dict_drawing:
     1249            tikz_pic += dict_drawing[v][0]
     1250        tikz_pic += '%%\n%%\n\\end{tikzpicture}'
     1251
     1252        return LatexExpr(tikz_pic)
     1253
     1254    def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color,
     1255                       opacity, vertex_color, axis):
     1256        r"""
     1257        Return a string ``tikz_pic`` consisting of a tikz picture of ``self``
     1258        according to a projection ``view`` and an angle ``angle``
     1259        obtained via Jmol through the current state property.
     1260
     1261        INPUT:
     1262
     1263        - ``view`` - list (default: [0,0,1]) representing the rotation axis.
     1264        - ``angle`` - integer angle of rotation in degree from 0 to 360.
     1265        - ``scale`` - integer specifying the scaling of the tikz picture.
     1266        - ``edge_color`` - string representing colors which tikz
     1267          recognize.
     1268        - ``facet_color`` - string representing colors which tikz
     1269          recognize.
     1270        - ``vertex_color`` - string representing colors which tikz
     1271          recognize.
     1272        - ``opacity`` - real number between 0 and 1 giving the opacity of
     1273          the front facets.
     1274        - ``axis`` - Boolean draw the axes at the origin or not.
     1275
     1276        OUTPUT:
     1277
     1278        - LatexExpr -- containing the TikZ picture.
     1279
     1280        EXAMPLE::
     1281
     1282            sage: P = Polyhedron(vertices=[[-1, -1, 2],[-1, 2, -1],[2, -1, -1]])
     1283            sage: P
     1284            A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices
     1285            sage: Image = P.projection()._tikz_2d_in_3d(view=[0.5,-1,-0.5], angle=55, scale=3, edge_color='blue!95!black', facet_color='orange', opacity=0.5, vertex_color='yellow', axis=True)
     1286            sage: print '\n'.join(Image.splitlines()[:4])
     1287            \begin{tikzpicture}%
     1288                [x={(0.644647cm, -0.476559cm)},
     1289                y={(0.192276cm, 0.857859cm)},
     1290                z={(-0.739905cm, -0.192276cm)},
     1291            sage: open('polytope-tikz3.tex', 'w').write(Image)    # not tested
     1292
     1293        .. NOTE::
     1294
     1295            The ``facet_color`` is the filing color of the polytope (polygon).
     1296        """
     1297        view_vector = vector(RDF, view)
     1298        rot = rotate_arbitrary(view_vector,-(angle/360)*2*pi)
     1299        rotation_matrix = rot[:2].transpose()
     1300
     1301        # Creates the nodes, coordinate and tag for every vertex of the polytope.
     1302        # The tag is used to draw the front facets later on.
     1303        dict_drawing = {}
     1304        edges = ''
     1305        for vert in self.points:
     1306            v = self.coords[vert]
     1307            v_vect = str([i.n(digits=3) for i in v])
     1308            v_vect = v_vect.replace('[','(')
     1309            v_vect = v_vect.replace(']',')')
     1310            tag = '%s' %v_vect
     1311            node = "\\node[%s] at %s     {};\n" % ('vertex', tag)
     1312            coord = '\coordinate %s at %s;\n' % (tag, tag)
     1313            dict_drawing[vert] = node, coord, tag
     1314
     1315        for index1, index2 in self.lines:
     1316            # v1 = self.coords[index1]
     1317            # v2 = self.coords[index2]
     1318            edges += "\\draw[%s] %s -- %s;\n" % ('edge',
     1319                                                 dict_drawing[index1][2],
     1320                                                 dict_drawing[index2][2])
     1321
     1322        # Start to write the output
     1323        tikz_pic = ''
     1324        tikz_pic += '\\begin{tikzpicture}%\n'
     1325        tikz_pic += '\t[x={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[0][0]),
     1326                                                RDF(rotation_matrix[0][1]))
     1327        tikz_pic += '\ty={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[1][0]),
     1328                                               RDF(rotation_matrix[1][1]))
     1329        tikz_pic += '\tz={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[2][0]),
     1330                                               RDF(rotation_matrix[2][1]))
     1331        tikz_pic += '\tscale=%f,\n' % scale
     1332        tikz_pic += '\tback/.style={loosely dotted, thin},\n'
     1333        tikz_pic += '\tedge/.style={color=%s, thick},\n' % edge_color
     1334        tikz_pic += '\tfacet/.style={fill=%s,fill opacity=%f},\n' % (facet_color,opacity)
     1335        tikz_pic += '\tvertex/.style={inner sep=1pt,circle,draw=%s!25!black,' % vertex_color
     1336        tikz_pic += 'fill=%s!75!black,thick,anchor=base}]\n%%\n%%\n' % vertex_color
     1337
     1338        # Draws the axes if True
     1339        if axis:
     1340            tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$};\n'
     1341            tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$};\n'
     1342            tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,0,1) node[anchor=south]{$z$};\n'
     1343
     1344        # Create the coordinate of the vertices:
     1345        tikz_pic += '%% Coordinate of the vertices:\n%%\n'
     1346        for v in dict_drawing:
     1347            tikz_pic += dict_drawing[v][1]
     1348
     1349        # Draw the interior by going in a cycle
     1350        vertices = list(self.parent_polyhedron.Vrep_generator())
     1351        tikz_pic += '%%\n%%\n%% Drawing the interior\n%%\n'
     1352        cyclic_vert = cyclic_sort_vertices_2d(list(self.parent_polyhedron.Vrep_generator()))
     1353        cyclic_indices = [vertices.index(v) for v in cyclic_vert]
     1354        tikz_pic += '\\fill[facet] '
     1355        for v in cyclic_indices:
     1356            if v in dict_drawing:
     1357                tikz_pic += '%s -- ' % dict_drawing[v][2]
     1358        tikz_pic += 'cycle {};\n'
     1359
     1360        # Draw the edges in the front
     1361        tikz_pic += '%%\n%%\n%% Drawing edges\n%%\n'
     1362        tikz_pic += edges
     1363
     1364        # Finally, the vertices in front are drawn on top of everything.
     1365        tikz_pic += '%%\n%%\n%% Drawing the vertices\n%%\n'
     1366        for v in dict_drawing:
     1367            tikz_pic += dict_drawing[v][0]
     1368        tikz_pic += '%%\n%%\n\\end{tikzpicture}'
     1369
     1370        return LatexExpr(tikz_pic)
     1371
     1372    def _tikz_3d_in_3d(self, view, angle, scale, edge_color,
     1373                       facet_color, opacity, vertex_color, axis):
     1374        r"""
     1375        Return a string ``tikz_pic`` consisting of a tikz picture of ``self``
     1376        according to a projection ``view`` and an angle ``angle``
     1377        obtained via Jmol through the current state property.
     1378
     1379        INPUT:
     1380
     1381        - ``view`` - list (default: [0,0,1]) representing the rotation axis.
     1382        - ``angle`` - integer angle of rotation in degree from 0 to 360.
     1383        - ``scale`` - integer specifying the scaling of the tikz picture.
     1384        - ``edge_color`` - string representing colors which tikz
     1385          recognize.
     1386        - ``facet_color`` - string representing colors which tikz
     1387          recognize.
     1388        - ``vertex_color`` - string representing colors which tikz
     1389          recognize.
     1390        - ``opacity`` - real number between 0 and 1 giving the opacity of
     1391          the front facets.
     1392        - ``axis`` - Boolean draw the axes at the origin or not.
     1393
     1394        OUTPUT:
     1395
     1396        - LatexExpr -- containing the TikZ picture.
     1397
     1398        EXAMPLES::
     1399
     1400            sage: P = polytopes.small_rhombicuboctahedron()
     1401            sage: Image = P.projection()._tikz_3d_in_3d([3,7,5], 100, scale=3, edge_color='blue', facet_color='orange', opacity=0.5, vertex_color='green', axis=True)
     1402            sage: type(Image)
     1403            <class 'sage.misc.latex.LatexExpr'>
     1404            sage: print '\n'.join(Image.splitlines()[:4])
     1405            \begin{tikzpicture}%
     1406                [x={(-0.046385cm, 0.837431cm)},
     1407                y={(-0.243536cm, 0.519228cm)},
     1408                z={(0.968782cm, 0.170622cm)},
     1409            sage: open('polytope-tikz1.tex', 'w').write(Image)    # not tested
     1410        """
     1411        view_vector = vector(RDF, view)
     1412        rot = rotate_arbitrary(view_vector, -(angle/360)*2*pi)
     1413        rotation_matrix = rot[:2].transpose()
     1414        proj_vector = (rot**(-1))*vector(RDF, [0, 0, 1])
     1415
     1416        # First compute the back and front vertices and facets
     1417        facets = self.face_inequalities
     1418        front_facets = []
     1419        back_facets = []
     1420        for index_facet in range(len(facets)):
     1421            A = facets[index_facet].vector()[1:]
     1422            B = facets[index_facet].vector()[0]
     1423            if A*(2000*proj_vector)+B < 0:
     1424                front_facets += [index_facet]
     1425            else:
     1426                back_facets += [index_facet]
     1427
     1428        vertices = list(self.parent_polyhedron.Vrep_generator())
     1429        front_vertices = []
     1430        for index_facet in front_facets:
     1431            A = facets[index_facet].vector()[1:]
     1432            B = facets[index_facet].vector()[0]
     1433            for v in self.points:
     1434                if A*self.coords[v]+B < 0.0005 and v not in front_vertices:
     1435                    front_vertices += [v]
     1436
     1437        back_vertices = []
     1438        for index_facet in back_facets:
     1439            A = facets[index_facet].vector()[1:]
     1440            B = facets[index_facet].vector()[0]
     1441            for v in self.points:
     1442                if A*self.coords[v]+B < 0.0005 and v not in back_vertices:
     1443                    back_vertices += [v]
     1444
     1445        # Creates the nodes, coordinate and tag for every vertex of the polytope.
     1446        # The tag is used to draw the front facets later on.
     1447        dict_drawing = {}
     1448        back_part = ''
     1449        front_part = ''
     1450
     1451        for vert in self.points:
     1452            v = self.coords[vert]
     1453            v_vect = str([i.n(digits=3) for i in v])
     1454            v_vect = v_vect.replace('[','(')
     1455            v_vect = v_vect.replace(']',')')
     1456            tag = '%s' %v_vect
     1457            node = "\\node[%s] at %s     {};\n" % ('vertex', tag)
     1458            coord = '\coordinate %s at %s;\n' %(tag, tag)
     1459            dict_drawing[vert] = node, coord, tag
     1460
     1461        # Separate the edges between back and front
     1462
     1463        for index1, index2 in self.lines:
     1464            # v1 = self.coords[index1]
     1465            # v2 = self.coords[index2]
     1466
     1467            H_v1 = set(self.parent_polyhedron.Vrepresentation(index1).incident())
     1468            H_v2 = set(self.parent_polyhedron.Vrepresentation(index2).incident())
     1469            H_v12 = [h for h in H_v1.intersection(H_v2) if h in back_facets]
     1470
     1471            # The back edge has to be between two vertices in the Back
     1472            # AND such that the 2 facets touching them are in the Back
     1473            if index1 in back_vertices and index2 in back_vertices and len(H_v12)==2:
     1474                back_part += "\\draw[%s,back] %s -- %s;\n" % ('edge', dict_drawing[index1][2], dict_drawing[index2][2])
     1475            else:
     1476                front_part += "\\draw[%s] %s -- %s;\n" % ('edge',dict_drawing[index1][2],dict_drawing[index2][2])
     1477
     1478        # Start to write the output
     1479        tikz_pic = ''
     1480        tikz_pic += '\\begin{tikzpicture}%\n'
     1481        tikz_pic += '\t[x={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[0][0]),
     1482                                                RDF(rotation_matrix[0][1]))
     1483        tikz_pic += '\ty={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[1][0]),
     1484                                               RDF(rotation_matrix[1][1]))
     1485        tikz_pic += '\tz={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[2][0]),
     1486                                               RDF(rotation_matrix[2][1]))
     1487        tikz_pic += '\tscale=%f,\n' % scale
     1488        tikz_pic += '\tback/.style={loosely dotted, thin},\n'
     1489        tikz_pic += '\tedge/.style={color=%s, thick},\n' % edge_color
     1490        tikz_pic += '\tfacet/.style={fill=%s,fill opacity=%f},\n' % (facet_color,opacity)
     1491        tikz_pic += '\tvertex/.style={inner sep=1pt,circle,draw=%s!25!black,' % vertex_color
     1492        tikz_pic += 'fill=%s!75!black,thick,anchor=base}]\n%%\n%%\n' % vertex_color
     1493
     1494        # Draws the axes if True
     1495        if axis:
     1496            tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$};\n'
     1497            tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$};\n'
     1498            tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,0,1) node[anchor=south]{$z$};\n'
     1499
     1500        # Create the coordinate of the vertices
     1501        tikz_pic += '%% Coordinate of the vertices:\n%%\n'
     1502        for v in dict_drawing:
     1503            tikz_pic += dict_drawing[v][1]
     1504
     1505        # Draw the edges in the back
     1506        tikz_pic += '%%\n%%\n%% Drawing edges in the back\n%%\n'
     1507        tikz_pic += back_part
     1508
     1509        # Draw the vertices on top of the back-edges
     1510        tikz_pic += '%%\n%%\n%% Drawing vertices in the back\n%%\n'
     1511        for v in back_vertices:
     1512            if not v in front_vertices and v in dict_drawing:
     1513                tikz_pic += dict_drawing[v][0]
     1514
     1515        # Draw the facets in the front by going in cycles for every facet.
     1516        tikz_pic += '%%\n%%\n%% Drawing the facets\n%%\n'
     1517        for index_facet in front_facets:
     1518            cyclic_vert = cyclic_sort_vertices_2d(list(facets[index_facet].incident()))
     1519            cyclic_indices = [vertices.index(v) for v in cyclic_vert]
     1520            tikz_pic += '\\fill[facet] '
     1521            for v in cyclic_indices:
     1522                if v in dict_drawing:
     1523                    tikz_pic += '%s -- ' % dict_drawing[v][2]
     1524            tikz_pic += 'cycle {};\n'
     1525
     1526        # Draw the edges in the front
     1527        tikz_pic += '%%\n%%\n%% Drawing edges in the front\n%%\n'
     1528        tikz_pic += front_part
     1529
     1530        # Finally, the vertices in front are drawn on top of everything.
     1531        tikz_pic += '%%\n%%\n%% Drawing the vertices in the front\n%%\n'
     1532        for v in self.points:
     1533            if v in front_vertices:
     1534                if v in dict_drawing:
     1535                    tikz_pic += dict_drawing[v][0]
     1536        tikz_pic += '%%\n%%\n\\end{tikzpicture}'
     1537        return LatexExpr(tikz_pic)