def tikz_code(self, pspict=None): from yanntricks.src.NoMathUtilities import logging symbol_dict = {} symbol_dict[None] = "$\\bullet$" symbol_dict["*"] = "$\\bullet$" symbol_dict["|"] = "$|$" symbol_dict["x"] = "$\\times$" symbol_dict["o"] = "$o$" symbol_dict["diamond"] = "$\diamondsuit$" try: effective_symbol = symbol_dict[self.parameters.symbol] except KeyError: effective_symbol = self.parameters.symbol if self.parameters.symbol == 'none': logging("You should use '' instead of 'none'", pspict=pspict) if self.parameters.symbol not in ["none", ""]: s = "\draw [{2}] {0} node [rotate={3}] {{{1}}};".format( self.coordinates(digits=5, pspict=pspict), effective_symbol, self.params(language="tikz", refute=["symbol", "dotangle"]), "DOTANGLE") if self.parameters.dotangle != None: s = s.replace("DOTANGLE", str(self.parameters.dotangle)) else: s = s.replace("DOTANGLE", "0") return s return ""
def id_values_dict(self): """ Build the dictionary of stored values in the auxiliary file and rewrite that file. """ d = {} try: f = open(self.interWriteFile.from_sage(), "r") except IOError: if not self.already_warned_CompileYourLaTeXFile: logging( f"Warning: the auxiliary file " f"{self.interWriteFile.from_main()} does not " f"seem to exist. Compile your LaTeX file.", pspict=self.picture) self.already_warned_CompileYourLaTeXFile = True return d idlist = f.read().replace('\n', '').replace(' ', '').replace('\\par', '').split("-") f.close() for els in idlist[0:-1]: key = els.split(":")[0] value = els.split(':')[1] d[key] = value with open(self.interWriteFile.from_sage(), "w") as f: for k in d: f.write("%s:%s-\n" % (k, d[k])) return d
def __sub__(self, other): try: s = AngleMeasure(value_radian=self.radian - other.radian) except AttributeError: from yanntricks.src.NoMathUtilities import logging logging( "Are you trying to add an 'AngleMesasure' with something else ?" ) logging("'other's type is " + str(type(other))) raise return s
def __add__(self, other): ## # return the sum of two angles. # The return type is `AngleMeasure` try: return AngleMeasure(value_radian=self.radian + other.radian) except AttributeError: from yanntricks.src.NoMathUtilities import logging logging( "Are you trying to add an 'AngleMeasure' with something else ?" ) logging("The other's type is " + str(type(other))) raise
def put_mark(self, dist=None, angle=None, text="", mark_point=None, added_angle=None, position=None, pspict=None, pspicts=None): """ Put a mark on an object If you want to put a mark on an object P.put_mark(0.1,text="foobar",pspict=pspict,position="N") mark_point is a function which returns the position of the mark point. If you give no position (i.e. no "S","N", etc.) the position will be automatic regarding the angle. - ``angle`` is given in degree. set `position` to "center" is dangerous because it puts the center of the box at given angle and distance. Thus the text can be ill placed, especially if the given `dist` is lower than the half of the box size. `center_direction` : the mark is placed in such a way that the center is at given angle, and the box's border at given distance. """ pspicts = make_psp_list(pspict, pspicts) for psp in pspicts: mark = self.get_mark(dist, angle, text, mark_point=mark_point, added_angle=added_angle, position=position, pspict=psp) if position in ["N", "S", "E", "W"] and angle is not None: logging("When you want a position like N,S,E, or W,\ the mark angle should not be given.") self.added_objects.append(psp, mark) self.mark = mark
def visual_vector(v, pspict=None, xunit=None, yunit=None): """ Return a vector which will be visually `self`. Return a vector at the same base as 'v' but such that it will visually appears as 'v' """ from yanntricks.src.NoMathUtilities import logging from yanntricks.src.affine_vector import AffineVector if pspict is None and (xunit is None or yunit is None): logging("Trying to make visual_vector with no pspict ?") raise DeprecationWarning if pspict: xunit = pspict.xunit yunit = pspict.yunit I = v.I F = I + (v.Dx / xunit, v.Dy / yunit) return AffineVector(I, F)
def is_almost_equal(self, other, epsilon=0.0001): ## # return true if `self` and `other` have coordinates difference # lower than `epsilon` # from yanntricks.src.NoMathUtilities import logging if not isinstance(other, Point): logging("We are comparing " + type(self) + " with " + type(other) + ". We continue, but this is strange.") sx = numerical_approx(self.x) sy = numerical_approx(self.y) ox = numerical_approx(other.x) oy = numerical_approx(other.y) if abs(sx - ox) > epsilon: return False if abs(sy - oy) > epsilon: return False return True
def get_Id_value(self, Id, default_value=0): if Id not in self.id_values_dict(): if not self.already_warned_CompileYourLaTeXFile: logging(self.picture.name + "-----") logging( f"Warning: the auxiliary file " f"{self.interWriteFile.from_main()} does not " f"contain the id «{Id}». Compile your LaTeX file.", pspict=self.picture) try: logging("Concerned tex expression : " f"{self.interId_to_tex_expression[Id]}") except KeyError: pass # when asking for a counter, not a box size. self.already_warned_CompileYourLaTeXFile = True return default_value value = self.id_values_dict()[Id] return value
def get_mark(self, dist, angle=None, text=None, mark_point=None, added_angle=None, position=None, pspict=None): # pylint:disable=too-many-branches """ - `angle` is degree or AngleMeasure In the internal representation of the mark, the angle type will be `AngleMeasure` """ from yanntricks.src.Constructors import Mark from yanntricks.src.AngleMeasure import AngleMeasure self.marque = True if position in ["N", "S", "E", "W"] and angle is not None: angle = None logging( f"When you want a position like N,S,E, or W, " f"the mark angle should not be given.", pspict=pspict) if angle is None and position not in ["N", "S", "E", "W"]: try: angle = self.advised_mark_angle(pspict=pspict) except AttributeError: angle = self.angle().degree + 90 if position == "center_direction": # In this case we assume 'self' is a point angle = angle.degree if isinstance(angle, AngleMeasure): angle = angle.degree # At this point, 'angle' has to be degree, # - for the possibility of "added_angle" # - the constructor of 'mark' expects degree or AngleMeasure if added_angle: angle = angle + added_angle if position is None: position = "corner" alpha = AngleMeasure(value_degree=angle).positive() deg = alpha.degree if deg == 0: position = "W" if deg == 90: position = "S" if deg == 180: position = "E" if deg == 180 + 90: position = "N" if position in ["N", "S", "E", "W"]: angle = None mark = Mark(graph=self, dist=dist, angle=angle, central_point=None, text=text, mark_point=mark_point, position=position, pspict=pspict) # In each .psttricks file we need the lines that make compute # the size of the text. Thus we call "get_box_size" for each. if not isinstance(pspict, list): pspict = [pspict] for psp in pspict: _, _ = psp.get_box_size(text) return mark
def get_mark(self, dist=None, angle=None, text=None, mark_point=None, added_angle=None, position=None, pspict=None, visual_work=True): from yanntricks.src.Visual import visual_point from yanntricks.src.Constructors import Mark if text == "" or text is None: logging( "This is very strange to require a mark with an empty text. Maybe you'll get a crash on the second pass." ) if visual_work: v_angle = inverse_visual_angle(self, pspict) old_xunit = pspict.xunit old_yunit = pspict.yunit pspict.xunit = 1 pspict.yunit = 1 mark = v_angle.get_mark(dist=dist, angle=angle, text=text, mark_point=mark_point, added_angle=added_angle, position=position, pspict=pspict, visual_work=False) pspict.xunit = old_xunit pspict.yunit = old_yunit cp = visual_point(mark.central_point(), pspict) return Mark(self, dist=None, angle=None, text=text, mark_point=None, central_point=cp, position=None, pspict=pspict) mark_point = self.mark_point(pspict) if position != None: print( "The mark of an angle should be given without position argument" ) raise # The default can be any value different than zero. It serves to # avoid a division by zero during the first compilation. dimx, dimy = pspict.get_box_size(text, default_value="3pt") # Now there are a lot of cases depending on the angles of the # two lines determining the angle AOB. # We will detail the computations for the case # 0<self.angleA.degree < 90 and 0<self.angleB.degree < 90 # The other cases are the same kind of trigonometry. # I just let you know that if you know 3 angles and one length # in a triangle, you know everything : # just draw the altitude and use Pythagoras along with some # trigonometry. # The cases are tested in the demo files # 'OMPAooMbyOIqeA' and 'Refraction' v = self._getOCvector(dimx, dimy, pspict=pspict) # If 'dist' is given, it overrides the computations of the # length of 'v' if dist is not None: if dist < v.length: logging("The distance you give is {} while I computed\ the minimal to be {}".format(dist, v.length), pspict=pspict) v = v.normalize(dist) # We impose a minimum for the v's length. # If the 'text' is small and the angle is large, its box is really # close to the angles'vertex. Thus the text will be very close to # the arc circle and the result is bad. # Thus we impose a minimal distance between the # arc circle and the mark. if dist is None: if v.length < 0.3: v = v.normalize(0.3) C = mark_point.translate(v) return Mark(self, dist=None, angle=None, text=text, mark_point=None, central_point=C, position=None, pspict=pspict)