| 4882 | def tikz(self, view=[0,0,1], rot_angle=0, scale=2, |
| 4883 | edge_color='blue!95!black', facet_color='blue!95!black', |
| 4884 | opacity=0.8, vertex_color='green', axis=False): |
| 4885 | """ |
| 4886 | Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` |
| 4887 | according to a projection ``view`` and an angle ``rot_angle`` |
| 4888 | obtained via Jmol through the current state property. |
| 4889 | |
| 4890 | INPUT: |
| 4891 | |
| 4892 | - ``view`` -- a list of length 3 representing a vector; |
| 4893 | - ``rot_angle`` -- an angle in degree from 0 to 360; |
| 4894 | - ``scale`` -- an integer specifying the scaling of the tikz picture; |
| 4895 | - ``edge_color``, ``facet_color``, ``vertex_color`` -- string representing |
| 4896 | colors which tikz recognize; |
| 4897 | - ``opacity`` -- a real number between 0 and 1 giving the opacity of |
| 4898 | the front facets; |
| 4899 | - ``axis`` -- a Boolean, to draw the axes at the origin. |
| 4900 | |
| 4901 | OUTPUT: |
| 4902 | |
| 4903 | - ``tikz_pic`` -- a string containing the raw text of a TikZ picture. |
| 4904 | |
| 4905 | .. NOTE:: |
| 4906 | |
| 4907 | The inputs ``view`` and ``rot_angle`` can be obtained from the viewer |
| 4908 | Jmol: |
| 4909 | |
| 4910 | 1) Right click on the image; |
| 4911 | 2) Select ``Console`; |
| 4912 | 3) Select the tab ``State`; |
| 4913 | 4) Scroll to the line ``moveto`` |
| 4914 | |
| 4915 | It read something like: |
| 4916 | |
| 4917 | moveto 0.0 {x y z angle} Scale |
| 4918 | |
| 4919 | The ``view`` is then [x,y,z] and ``rot_angle`` is angle. |
| 4920 | The following number is the scale. |
| 4921 | |
| 4922 | EXAMPLES:: |
| 4923 | |
| 4924 | sage: P1 = polytopes.small_rhombicuboctahedron() |
| 4925 | sage: Image1 = P1.tikz([1,3,5], 175, scale=4) |
| 4926 | sage: open('polytope-tikz.tex', 'w').write(Image1) |
| 4927 | |
| 4928 | sage: P2 = Polyhedron(vertices=[[1, 1],[1, 2],[2, 1]]) |
| 4929 | sage: Image2 = P2.tikz(scale=3, edge_color='blue!95!black', facet_color='orange!95!black', opacity=0.4, vertex_color='yellow', axis=True) |
| 4930 | sage: open('polytope-tikz2.tex', 'w').write(Image2) |
| 4931 | |
| 4932 | sage: P3 = Polyhedron(vertices=[[-1, -1, 2],[-1, 2, -1],[2, -1, -1]]) |
| 4933 | sage: P3 |
| 4934 | A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices. |
| 4935 | sage: Image3 = P3.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) |
| 4936 | sage: open('polytope-tikz3.tex', 'w').write(Image3) |
| 4937 | |
| 4938 | sage: P=Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]]) |
| 4939 | sage: P |
| 4940 | A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 5 vertices. |
| 4941 | sage: P.tikz() |
| 4942 | Traceback (most recent call last): |
| 4943 | ... |
| 4944 | NotImplementedError: The polytope has to live in 2 or 3 dimensions. |
| 4945 | |
| 4946 | |
| 4947 | .. TO DO:: |
| 4948 | |
| 4949 | Make it possible to draw Schlegel diagram for 4-polytope. |
| 4950 | |
| 4951 | sage: P=Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]]) |
| 4952 | sage: P |
| 4953 | A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 5 vertices. |
| 4954 | sage: P.tikz() |
| 4955 | Traceback (most recent call last): |
| 4956 | ... |
| 4957 | NotImplementedError: The polytope has to live in 2 or 3 dimensions. |
| 4958 | |
| 4959 | Make it possible to draw 3-polytope living in higher dimension. |
| 4960 | |
| 4961 | """ |
| 4962 | if self.ambient_dim() > 3 or self.ambient_dim() < 2: |
| 4963 | raise NotImplementedError("The polytope has to live in 2 or 3 dimensions.") |
| 4964 | elif self.ambient_dim() == 2: |
| 4965 | return self._tikz_2d(scale, edge_color, facet_color, opacity, |
| 4966 | vertex_color, axis) |
| 4967 | elif self.dim() == 2: |
| 4968 | return self._tikz_2d_in_3d(view, rot_angle, scale, edge_color, |
| 4969 | facet_color, opacity, vertex_color, axis) |
| 4970 | else: |
| 4971 | return self._tikz_3d_in_3d(view, rot_angle, scale, edge_color, |
| 4972 | facet_color, opacity, vertex_color, axis) |
| 4973 | |
| 4974 | def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): |
| 4975 | """ |
| 4976 | Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` |
| 4977 | |
| 4978 | INPUT: |
| 4979 | |
| 4980 | - ``scale`` -- an integer specifying the scaling of the tikz picture; |
| 4981 | - ``edge_color``, ``facet_color``, ``vertex_color`` -- string representing |
| 4982 | colors which tikz recognize; |
| 4983 | - ``opacity`` -- a real number between 0 and 1 giving the opacity of |
| 4984 | the front facets; |
| 4985 | - ``axis`` -- a Boolean, to draw the axes at the origin. |
| 4986 | |
| 4987 | .. NOTE:: |
| 4988 | |
| 4989 | The ``facet_color`` is the filing color of the polytope (polygon). |
| 4990 | """ |
| 4991 | |
| 4992 | # Creates the nodes, coordinate and tag for every vertex of the polytope. |
| 4993 | # The tag is used to draw the front facets later on. |
| 4994 | dict_drawing = {} |
| 4995 | edges = '' |
| 4996 | for v in self.Vrep_generator(): |
| 4997 | v_vect = str([i.n(digits=3) for i in v.vector()]) |
| 4998 | v_vect = v_vect.replace('[','(') |
| 4999 | v_vect = v_vect.replace(']',')') |
| 5000 | tag = '%s' %v_vect |
| 5001 | node = "\\node[%s] at %s {};\n" %('vertex',tag) |
| 5002 | |
| 5003 | for nei in v.neighbors(): |
| 5004 | nei_vect = str([i.n(digits=3) for i in nei.vector()]) |
| 5005 | nei_vect = nei_vect.replace('[','(') |
| 5006 | nei_vect = nei_vect.replace(']',')') |
| 5007 | tag_nei = '%s' %nei_vect |
| 5008 | edges += "\\draw[%s] %s -- %s;\n" %('edge',tag,tag_nei) |
| 5009 | |
| 5010 | coord = '\coordinate %s at %s;\n' %(tag,tag) |
| 5011 | dict_drawing[v] = node,coord,tag |
| 5012 | |
| 5013 | # Start to write the output |
| 5014 | tikz_pic = '' |
| 5015 | tikz_pic += '\\begin{tikzpicture}%\n' |
| 5016 | tikz_pic += '\t[scale=%f,\n' %scale |
| 5017 | tikz_pic += '\tback/.style={loosely dotted, thin},\n' |
| 5018 | tikz_pic += '\tedge/.style={color=%s, thick},\n' %edge_color |
| 5019 | tikz_pic += '\tfacet/.style={fill=%s,fill opacity=%f},\n' %(facet_color,opacity) |
| 5020 | tikz_pic += '\tvertex/.style={inner sep=1pt,circle,draw=%s!25!black,' %vertex_color |
| 5021 | tikz_pic += 'fill=%s!75!black,thick,anchor=base}]\n\n\n' %vertex_color |
| 5022 | |
| 5023 | # Draws the axes if True |
| 5024 | if axis: |
| 5025 | tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$};\n' |
| 5026 | tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$};\n' |
| 5027 | |
| 5028 | # Create the coordinate of the vertices: |
| 5029 | tikz_pic += '%% Coordinate of the vertices:\n\n' |
| 5030 | for v in self.Vrep_generator(): |
| 5031 | tikz_pic += dict_drawing[v][1] |
| 5032 | |
| 5033 | # Draw the interior by going in a cycle |
| 5034 | tikz_pic += '\n\n%% Drawing the interior\n\n' |
| 5035 | cyclic_vert = cyclic_sort_vertices_2d(list(self.Vrep_generator())) |
| 5036 | tikz_pic += '\\fill[facet] ' |
| 5037 | for v in cyclic_vert: |
| 5038 | tikz_pic += '%s -- ' %dict_drawing[v][2] |
| 5039 | tikz_pic += 'cycle {};\n' |
| 5040 | |
| 5041 | # Draw the edges in the front |
| 5042 | tikz_pic += '\n\n%% Drawing edges in the front\n\n' |
| 5043 | tikz_pic += edges |
| 5044 | |
| 5045 | # Finally, the vertices in front are drawn on top of everything. |
| 5046 | tikz_pic += '\n\n%% Drawing the vertices in the front\n\n' |
| 5047 | for v in self.Vrep_generator(): |
| 5048 | tikz_pic += dict_drawing[v][0] |
| 5049 | tikz_pic += '\n\n\\end{tikzpicture}' |
| 5050 | |
| 5051 | return tikz_pic |
| 5052 | |
| 5053 | def _tikz_2d_in_3d(self, view, rot_angle, scale, edge_color, facet_color, |
| 5054 | opacity, vertex_color, axis): |
| 5055 | """ |
| 5056 | Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` |
| 5057 | according to a projection ``view`` and an angle ``rot_angle`` |
| 5058 | obtained via Jmol through the current state property. |
| 5059 | |
| 5060 | INPUT: |
| 5061 | |
| 5062 | - ``view`` -- a list of length 3 representing a vector; |
| 5063 | - ``rot_angle`` -- an angle in degree from 0 to 360 (rotation along the view); |
| 5064 | - ``scale`` -- an integer specifying the scaling of the tikz picture; |
| 5065 | - ``edge_color``, ``facet_color``, ``vertex_color`` -- string |
| 5066 | representing colors which tikz recognize; |
| 5067 | - ``opacity`` -- a real number between 0 and 1 giving the opacity of |
| 5068 | the front facets; |
| 5069 | - ``axis`` -- a Boolean, to draw the axes at the origin. |
| 5070 | |
| 5071 | .. NOTE:: |
| 5072 | |
| 5073 | The ``facet_color`` is the filing color of the polytope (polygon). |
| 5074 | |
| 5075 | """ |
| 5076 | |
| 5077 | V = VectorSpace(RDF,3) |
| 5078 | view_vector = V(view) |
| 5079 | rot = rotate_arbitrary(view_vector,-(rot_angle/360)*2*pi) |
| 5080 | rotation_matrix = rot[:2].transpose() |
| 5081 | |
| 5082 | # Creates the nodes, coordinate and tag for every vertex of the polytope. |
| 5083 | # The tag is used to draw the front facets later on. |
| 5084 | dict_drawing = {} |
| 5085 | edges = '' |
| 5086 | for v in self.Vrep_generator(): |
| 5087 | v_vect = str([i.n(digits=3) for i in v.vector()]) |
| 5088 | v_vect = v_vect.replace('[','(') |
| 5089 | v_vect = v_vect.replace(']',')') |
| 5090 | tag = '%s' %v_vect |
| 5091 | node = "\\node[%s] at %s {};\n" %('vertex',tag) |
| 5092 | |
| 5093 | for nei in v.neighbors(): |
| 5094 | nei_vect = str([i.n(digits=3) for i in nei.vector()]) |
| 5095 | nei_vect = nei_vect.replace('[','(') |
| 5096 | nei_vect = nei_vect.replace(']',')') |
| 5097 | tag_nei = '%s' %nei_vect |
| 5098 | edges += "\\draw[%s] %s -- %s;\n" %('edge',tag,tag_nei) |
| 5099 | |
| 5100 | coord = '\coordinate %s at %s;\n' %(tag,tag) |
| 5101 | dict_drawing[v] = node,coord,tag |
| 5102 | |
| 5103 | # Start to write the output |
| 5104 | tikz_pic = '' |
| 5105 | tikz_pic += '\\begin{tikzpicture}%\n' |
| 5106 | tikz_pic += '\t[x={(%fcm, %fcm)},\n' %(n(rotation_matrix[0][0]),n(rotation_matrix[0][1])) |
| 5107 | tikz_pic += '\ty={(%fcm, %fcm)},\n' %(n(rotation_matrix[1][0]),n(rotation_matrix[1][1])) |
| 5108 | tikz_pic += '\tz={(%fcm, %fcm)},\n' %(n(rotation_matrix[2][0]),n(rotation_matrix[2][1])) |
| 5109 | tikz_pic += '\tscale=%f,\n' %scale |
| 5110 | tikz_pic += '\tback/.style={loosely dotted, thin},\n' |
| 5111 | tikz_pic += '\tedge/.style={color=%s, thick},\n' %edge_color |
| 5112 | tikz_pic += '\tfacet/.style={fill=%s,fill opacity=%f},\n' %(facet_color,opacity) |
| 5113 | tikz_pic += '\tvertex/.style={inner sep=1pt,circle,draw=%s!25!black,' %vertex_color |
| 5114 | tikz_pic += 'fill=%s!75!black,thick,anchor=base}]\n\n\n' %vertex_color |
| 5115 | |
| 5116 | # Draws the axes if True |
| 5117 | if axis: |
| 5118 | tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$};\n' |
| 5119 | tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$};\n' |
| 5120 | tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,0,1) node[anchor=south]{$z$};\n' |
| 5121 | |
| 5122 | # Create the coordinate of the vertices: |
| 5123 | tikz_pic += '%% Coordinate of the vertices:\n\n' |
| 5124 | for v in self.Vrep_generator(): |
| 5125 | tikz_pic += dict_drawing[v][1] |
| 5126 | |
| 5127 | # Draw the interior by going in a cycle |
| 5128 | tikz_pic += '\n\n%% Drawing the interior\n\n' |
| 5129 | cyclic_vert = cyclic_sort_vertices_2d(list(self.Vrep_generator())) |
| 5130 | tikz_pic += '\\fill[facet] ' |
| 5131 | for v in cyclic_vert: |
| 5132 | tikz_pic += '%s -- ' %dict_drawing[v][2] |
| 5133 | tikz_pic += 'cycle {};\n' |
| 5134 | |
| 5135 | # Draw the edges in the front |
| 5136 | tikz_pic += '\n\n%% Drawing edges in the front\n\n' |
| 5137 | tikz_pic += edges |
| 5138 | |
| 5139 | # Finally, the vertices in front are drawn on top of everything. |
| 5140 | tikz_pic += '\n\n%% Drawing the vertices in the front\n\n' |
| 5141 | for v in self.Vrep_generator(): |
| 5142 | tikz_pic += dict_drawing[v][0] |
| 5143 | tikz_pic += '\n\n\\end{tikzpicture}' |
| 5144 | |
| 5145 | return tikz_pic |
| 5146 | |
| 5147 | def _tikz_3d_in_3d(self, view, rot_angle, scale, edge_color, |
| 5148 | facet_color, opacity, vertex_color, axis): |
| 5149 | """ |
| 5150 | Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` |
| 5151 | according to a projection ``view`` and an angle ``rot_angle`` |
| 5152 | obtained via Jmol through the current state property. |
| 5153 | |
| 5154 | INPUT: |
| 5155 | |
| 5156 | - ``view`` -- a list of length 3 representing a vector; |
| 5157 | - ``rot_angle`` -- an angle in degree from 0 to 360; |
| 5158 | - ``scale`` -- an integer specifying the scaling of the tikz picture; |
| 5159 | - ``edge_color``, ``facet_color``, ``vertex_color`` -- string |
| 5160 | representing colors which tikz recognize; |
| 5161 | - ``opacity`` -- a real number between 0 and 1 giving the opacity of |
| 5162 | the front facets; |
| 5163 | - ``axis`` -- a Boolean, to draw the axes at the origin. |
| 5164 | |
| 5165 | """ |
| 5166 | V = VectorSpace(RDF,3) |
| 5167 | view_vector = V(view) |
| 5168 | rot = rotate_arbitrary(view_vector,-(rot_angle/360)*2*pi) |
| 5169 | rotation_matrix = rot[:2].transpose() |
| 5170 | proj_vector = (rot**(-1))*V([0,0,1]) |
| 5171 | |
| 5172 | # First compute the back and front vertices and facets |
| 5173 | front_facets = [] |
| 5174 | back_facets = [] |
| 5175 | for facet in self.Hrep_generator(): |
| 5176 | A = facet.vector()[1:] |
| 5177 | B = facet.vector()[0] |
| 5178 | if A*(2000*proj_vector)+B<0: |
| 5179 | front_facets += [facet] |
| 5180 | else: |
| 5181 | back_facets += [facet] |
| 5182 | |
| 5183 | front_vertices = [] |
| 5184 | for facet in front_facets: |
| 5185 | A = facet.vector()[1:] |
| 5186 | B = facet.vector()[0] |
| 5187 | for v in self.Vrep_generator(): |
| 5188 | if A*v.vector()+B<0.0005: |
| 5189 | front_vertices += [v] |
| 5190 | |
| 5191 | back_vertices = [] |
| 5192 | for facet in back_facets: |
| 5193 | A = facet.vector()[1:] |
| 5194 | B = facet.vector()[0] |
| 5195 | for v in self.Vrep_generator(): |
| 5196 | if A*v.vector()+B<0.0005: |
| 5197 | back_vertices += [v] |
| 5198 | |
| 5199 | # Creates the nodes, coordinate and tag for every vertex of the polytope. |
| 5200 | # The tag is used to draw the front facets later on. |
| 5201 | dict_drawing = {} |
| 5202 | first_part = '' |
| 5203 | second_part = '' |
| 5204 | for v in self.Vrep_generator(): |
| 5205 | v_vect = str([i.n(digits=3) for i in v.vector()]) |
| 5206 | v_vect = v_vect.replace('[','(') |
| 5207 | v_vect = v_vect.replace(']',')') |
| 5208 | tag = '%s' %v_vect |
| 5209 | node = "\\node[%s] at %s {};\n" %('vertex',tag) |
| 5210 | for nei in v.neighbors(): |
| 5211 | nei_vect = str([i.n(digits=3) for i in nei.vector()]) |
| 5212 | nei_vect = nei_vect.replace('[','(') |
| 5213 | nei_vect = nei_vect.replace(']',')') |
| 5214 | tag_nei = '%s' %nei_vect |
| 5215 | H_v = set(v.incident()) |
| 5216 | H_nei = set(nei.incident()) |
| 5217 | H_v_nei = [h in back_facets for h in H_v.intersection(H_nei)] |
| 5218 | |
| 5219 | # The back edge has to be between two vertices in the Back |
| 5220 | # AND such that the 2 facets touching them are in the Back |
| 5221 | if v in back_vertices and nei in back_vertices and sum(H_v_nei)==2: |
| 5222 | first_part += "\\draw[%s,back] %s -- %s;\n" %('edge',tag,tag_nei) |
| 5223 | else: |
| 5224 | second_part += "\\draw[%s] %s -- %s;\n" %('edge',tag,tag_nei) |
| 5225 | coord = '\coordinate %s at %s;\n' %(tag,tag) |
| 5226 | dict_drawing[v] = node,coord,tag |
| 5227 | |
| 5228 | # Start to write the output |
| 5229 | tikz_pic = '' |
| 5230 | tikz_pic += '\\begin{tikzpicture}%\n' |
| 5231 | tikz_pic += '\t[x={(%fcm, %fcm)},\n' %(n(rotation_matrix[0][0]),n(rotation_matrix[0][1])) |
| 5232 | tikz_pic += '\ty={(%fcm, %fcm)},\n' %(n(rotation_matrix[1][0]),n(rotation_matrix[1][1])) |
| 5233 | tikz_pic += '\tz={(%fcm, %fcm)},\n' %(n(rotation_matrix[2][0]),n(rotation_matrix[2][1])) |
| 5234 | tikz_pic += '\tscale=%f,\n' %scale |
| 5235 | tikz_pic += '\tback/.style={loosely dotted, thin},\n' |
| 5236 | tikz_pic += '\tedge/.style={color=%s, thick},\n' %edge_color |
| 5237 | tikz_pic += '\tfacet/.style={fill=%s,fill opacity=%f},\n' %(facet_color,opacity) |
| 5238 | tikz_pic += '\tvertex/.style={inner sep=1pt,circle,draw=%s!25!black,' %vertex_color |
| 5239 | tikz_pic += 'fill=%s!75!black,thick,anchor=base}]\n\n\n' %vertex_color |
| 5240 | |
| 5241 | # Draws the axes if True |
| 5242 | if axis: |
| 5243 | tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$};\n' |
| 5244 | tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$};\n' |
| 5245 | tikz_pic += '\\draw[color=black,thick,->] (0,0,0) -- (0,0,1) node[anchor=south]{$z$};\n' |
| 5246 | |
| 5247 | # Create the coordinate of the vertices |
| 5248 | tikz_pic += '%% Coordinate of the vertices:\n\n' |
| 5249 | for v in self.Vrep_generator(): |
| 5250 | tikz_pic += dict_drawing[v][1] |
| 5251 | |
| 5252 | # Draw the edges in the back |
| 5253 | tikz_pic += '\n\n%% Drawing edges in the back\n\n' |
| 5254 | tikz_pic += first_part |
| 5255 | |
| 5256 | # Draw the vertices on top of the back-edges |
| 5257 | tikz_pic += '\n\n%% Drawing vertices in the back\n\n' |
| 5258 | for v in self.Vrep_generator(): |
| 5259 | if v in back_vertices and v not in front_vertices: |
| 5260 | tikz_pic += dict_drawing[v][0] |
| 5261 | |
| 5262 | # Draw the facets in the front by going in cycles for every facet. |
| 5263 | tikz_pic += '\n\n%% Drawing the facets\n\n' |
| 5264 | for facet in front_facets: |
| 5265 | cyclic_vert = cyclic_sort_vertices_2d(list(facet.incident())) |
| 5266 | tikz_pic += '\\fill[facet] ' |
| 5267 | for v in cyclic_vert: |
| 5268 | tikz_pic += '%s -- ' %dict_drawing[v][2] |
| 5269 | tikz_pic += 'cycle {};\n' |
| 5270 | |
| 5271 | # Draw the edges in the front |
| 5272 | tikz_pic += '\n\n%% Drawing edges in the front\n\n' |
| 5273 | tikz_pic += second_part |
| 5274 | |
| 5275 | # Finally, the vertices in front are drawn on top of everything. |
| 5276 | tikz_pic += '\n\n%% Drawing the vertices in the front\n\n' |
| 5277 | for v in self.Vrep_generator(): |
| 5278 | if v in front_vertices: |
| 5279 | tikz_pic += dict_drawing[v][0] |
| 5280 | tikz_pic += '\n\n\\end{tikzpicture}' |
| 5281 | |
| 5282 | return tikz_pic |