/// <summary> /// Creates a 2D rotation. /// </summary> /// <param name="angle">The angle in radians.</param> /// <returns></returns> public static TikzMatrix RotationMatrix(double angle) { TikzMatrix ret = new TikzMatrix(); ret.m[0, 0] = ret.m[1, 1] =Math.Cos(angle); ret.m[0, 1] = -Math.Sin(angle); ret.m[1, 0] = -ret.m[0, 1]; return ret; }
public Parser.TikzMatrix GetTikzToScreenTransform() { Parser.TikzMatrix AbsTikzToScreen = new Parser.TikzMatrix(); AbsTikzToScreen.m[0, 0] = View.Resolution; AbsTikzToScreen.m[1, 1] = -View.Resolution; AbsTikzToScreen.m[0, 2] = -View.Resolution * View.BB.X; AbsTikzToScreen.m[1, 2] = View.Resolution * (View.BB.Height + View.BB.Y); Parser.TikzMatrix total = AbsTikzToScreen * View.CoordinateTransform; return total; }
public TikzMatrix Inverse() { TikzMatrix mi = new TikzMatrix(); double d = Det(); mi.m[0,0] = m[1, 1] / d; mi.m[1, 0] = -m[1, 0] / d; mi.m[0, 1] = -m[0, 1] / d; mi.m[1, 1] = m[0, 0] / d; mi.m[0, 2] = - mi.m[0,0] * m[0,2] - mi.m[0,1]*m[1,2]; mi.m[1, 2] = - mi.m[1,0] * m[0, 2] - mi.m[1, 1] * m[1, 2]; return mi; }
public static TikzMatrix ZeroMatrix() { TikzMatrix ret = new TikzMatrix(); ret.m[0, 0] = 0; ret.m[1, 1] = 0; return ret; }
/// <summary> /// Same as above, but additionally the editable shift is returned. /// (or null if a new one needs to be created) /// </summary> /// <param name="ret"></param> /// <param name="EditableShift"></param> /// <returns></returns> bool GetTransformAtEditableShift(out TikzMatrix ret, out Tikz_Option EditableShift) { ret = new TikzMatrix(); // stores the coord trsf. at current position EditableShift = null; if (!parent.GetCurrentTransformAt(this, out ret)) return false; //bool foundone = false; foreach (TikzParseItem tpi in Children) { if (tpi is Tikz_Option) { Tikz_Option to = tpi as Tikz_Option; if (to.type == Tikz_OptionType.keyval && to.key.Trim() == "shift") { if (to.coordval == null) return false; if (to.coordval.type == Tikz_CoordType.Cartesian) { // we found one (yoohoo) EditableShift = to; return true; } } if (!TransformFromOption(to, ret, out ret)) return false; // invalid coord trafo encountered -> report failure } } EditableShift = null; // nothing found -> return null return true; }
/// <summary> /// It returns, if possible, the coordinate transformation at the shift=... option that will /// be editted by SetShiftRel(). This method is in particular used by PdfOverlay to draw the raster associated /// to a scope object. /// </summary> /// <param name="ret"></param> /// <returns>true on success, false if coord trafo could not be determined</returns> public bool GetTransformAtEditableShift(out TikzMatrix ret) { Tikz_Option dummy; return GetTransformAtEditableShift(out ret, out dummy); }
/// <summary> /// Returns the coordinate transfor corresponding to an option, if possible. /// If the option is not relevant for coordinate tranformation (or not supported), true is returned /// and newTrafo = oldTrafo. If the option is recognized, but the value cannot be determined, /// false is returned and newTrafo shouldn't be used. /// </summary> /// <param name="to"></param> /// <param name="oldTrafo"></param> /// <param name="newTrafo"></param> /// <returns></returns> bool TransformFromOption(Tikz_Option to, TikzMatrix oldTrafo, out TikzMatrix newTrafo) { TikzMatrix ret = new TikzMatrix(); newTrafo = ret; if (to.type == Tikz_OptionType.keyval) { switch (to.key.Trim()) { case "xscale": if (to.numval == null) return false; ret.m[0, 0] = to.numval.GetInCM(); break; case "yscale": if (to.numval == null) return false; ret.m[1, 1] = to.numval.GetInCM(); break; case "scale": if (to.numval == null) return false; ret.m[0, 0] = to.numval.GetInCM(); ret.m[1, 1] = ret.m[0, 0]; break; case "xshift": if (to.numval == null) return false; ret.m[0, 2] = to.numval.GetInCM("pt"); break; case "yshift": if (to.numval == null) return false; ret.m[1, 2] = to.numval.GetInCM("pt"); break; case "shift": // shift is complicated..... if (to.coordval == null) return false; if (to.coordval.type == Tikz_CoordType.Named) { // for named coord, shift sets the _absolute_ origin of the coord system // hence we need the absolute coord trafo at the current point! Point neworig; if (!to.coordval.GetAbsPos(out neworig, this)) return false; TikzMatrix Mabs; if (!parent.GetCurrentTransformAt(this, out Mabs)) return false; Mabs = Mabs * oldTrafo; Point theshift = Mabs.Inverse().Transform(neworig); ret.m[0, 2] = theshift.X; ret.m[1, 2] = theshift.Y; } else if (to.coordval.type == Tikz_CoordType.Cartesian || to.coordval.type == Tikz_CoordType.Polar) { Point p = to.coordval.GetCartesian(); ret.m[0, 2] = p.X; ret.m[1, 2] = p.Y; } else { // invalid coordinate value return false; } break; case "rotate": if (to.numval == null) return false; double angle = to.numval.GetInCM() * 2* Math.PI / 360; ret.m[0, 0] = Math.Cos(angle); ret.m[1, 0] = Math.Sin(angle); ret.m[0, 1] = -Math.Sin(angle); ret.m[1, 1] = Math.Cos(angle); break; case "xslant": if (to.numval == null) return false; double amount = to.numval.GetInCM(); ret.m[0, 0] = 1; ret.m[1, 0] = 0; ret.m[0, 1] = amount; ret.m[1, 1] = 1; break; case "yslant": if (to.numval == null) return false; amount = to.numval.GetInCM(); ret.m[0, 0] = 1; ret.m[1, 0] = amount; ret.m[0, 1] = 0; ret.m[1, 1] = 1; break; default: // option not relevant for coordinate computation (or not supported) -> ignore newTrafo = oldTrafo; return true; } } // if we get here, the option was recognized as relevant for coordinate transf., and the value could be read newTrafo = oldTrafo * ret; return true; }
//public List<Tikz_Option> options = new List<Tikz_Option>(); // public static Tikz_Options FromCommonTree(CommonTree t) // { // IM_NODE OPTIONS? nodename? coord? STRING // Tikz_Options opts = new Tikz_Options(); // foreach (CommonTree tt in t.Children) // { // Tikz_Option to = Tikz_Option.FromCommonTree(tt); // if (to != null) // opts.options.Add(to); // } // return opts; // } /* public static TikzMatrix GetTransform(TikzContainerParseItem tcpi) { TikzMatrix ret = new TikzMatrix(); double scale = 1, xshift = 0, yshift = 0; Tikz_Option o = GetOption(tcpi, "xshift", Tikz_OptionType.keyval); if (o != null) if (o.numval != null) xshift = o.numval.GetInCM(); o = GetOption(tcpi, "yshift", Tikz_OptionType.keyval); if (o != null) if (o.numval != null) yshift = o.numval.GetInCM(); o = GetOption(tcpi, "scale", Tikz_OptionType.keyval); if (o != null) if (o.numval != null) scale = o.numval.GetInCM(); ret.m[0, 0] = scale; ret.m[1, 1] = scale; ret.m[0, 2] = xshift; ret.m[1, 2] = yshift; return ret; } */ /// <summary> /// Gets the total coordinate transformation that is encoded in this options block. /// How this apparently works in Tikz is as follows: /// (determined by trial and error rather than specification, so hope for the best...) /// - for each relevant option (shift, xshift, yshift, scale, xscale, yscale) a separate transformation is produced /// - all those transformations are multiplied /// </summary> /// <returns></returns> public bool GetTransform(out TikzMatrix ret) { ret = new TikzMatrix(); // start with unit matrix foreach (TikzParseItem tpi in Children) { if (tpi is Tikz_Option) { Tikz_Option to = tpi as Tikz_Option; if (!TransformFromOption(to, ret, out ret)) return false; } } return true; /* double scale=1, xshift=0, yshift=0, xscale=1, yscale=1; Tikz_Option o = GetOption("xshift", Tikz_OptionType.keyval); if (o != null) if (o.numval != null) xshift = o.numval.GetInCM("pt"); o = GetOption("yshift", Tikz_OptionType.keyval); if (o != null) if (o.numval != null) yshift = o.numval.GetInCM("pt"); o = GetOption("scale", Tikz_OptionType.keyval); if (o != null) if (o.numval != null) scale = o.numval.GetInCM(); o = GetOption("xscale", Tikz_OptionType.keyval); if (o != null) if (o.numval != null) xscale = o.numval.GetInCM(); o = GetOption("yscale", Tikz_OptionType.keyval); if (o != null) if (o.numval != null) yscale = o.numval.GetInCM(); ret.m[0, 0] = scale * xscale; ret.m[1, 1] = scale * yscale; ret.m[0, 2] = xshift; ret.m[1, 2] = yshift; */ //return ret; }
/// <summary> /// This method determines the coord transform that should be used for rasterizing the scope's /// shift. Note that this is tricky since a scope per se does not have an anchor point. /// We take here as anchor point (i.e., the image of (0,0) under returned coord transformation) /// the transformed origin of the coordinate system at the position of the editable option shift=... /// that determines the scope's position. /// </summary> /// <param name="ret"></param> /// <returns></returns> public bool GetRasterTransform(out TikzMatrix ret) { if (options != null) return options.GetTransformAtEditableShift(out ret); else return parent.GetCurrentTransformAt(this, out ret); }
/* public TikzMatrix GetCurrentTransform() { TikzMatrix M; //M = Tikz_Options.GetTransform(this); if (options != null) M = options.GetTransform(); else M = new TikzMatrix(); if (parent != null) M = parent.GetCurrentTransform() * M; return M; } */ /// <summary> /// Determines the coordinate transformation at object childtpi, /// or at the end of the container in case childtpi is null. /// </summary> /// <param name="childtpi">The object to determine coordinate trsf. at.</param> /// <returns>The coordinate transformation.</returns> public bool GetCurrentTransformAt(TikzParseItem childtpi, out TikzMatrix M) { if (parent != null) { if (!parent.GetCurrentTransformAt(this, out M)) return false; } else M = new TikzMatrix(); // identity matrix foreach (TikzParseItem tpi in Children) { if (tpi == childtpi && childtpi != null) { break; } else if (tpi is Tikz_Options) { TikzMatrix MM; if ((tpi as Tikz_Options).GetTransform(out MM)) M = M * MM; else return false; } } return true; }
public void SetCorrectRaster(TikzParseItem tpi, bool IsParent = false) { if (ParseTree == null) return; if (tpi == null) { Tikz_Picture tp = ParseTree.GetTikzPicture(); if (tp != null) { TikzMatrix M; if (!tp.GetCurrentTransformAt(null, out M)) Rasterizer.View.CoordinateTransform = new TikzMatrix(); // if the program gets here, the global coord. transformation could not be understood->ovelay should display nothing else Rasterizer.View.CoordinateTransform = M; //rasterizer.RasterOrigin = M.Transform(new Point(0, 0)); //rasterizer.RasterScale = M.m[1, 1]; Rasterizer.View.IsCartesian = !UsePolarCoordinates; } } else if (tpi is Tikz_Scope) { Tikz_Scope ts = tpi as Tikz_Scope; TikzMatrix M; if (IsParent) { if (!ts.GetCurrentTransformAt(null, out M)) // todo M = new TikzMatrix(); // broken coords-> take unity as backup } else { //if (!ts.parent.GetCurrentTransformAt(ts, out M)) // M = new TikzMatrix(); if (!ts.GetRasterTransform(out M)) M = new TikzMatrix(); } Rasterizer.View.CoordinateTransform = M; //rasterizer.RasterOrigin = M.Transform(new Point(0, 0)); //rasterizer.RasterScale = M.m[1, 1]; Rasterizer.View.IsCartesian = !IsParent || !UsePolarCoordinates; } else if (tpi is Tikz_XYItem) { Tikz_XYItem t = tpi as Tikz_XYItem; Point offset; if (t.GetAbsPos(out offset, true)) { TikzMatrix M; if (!t.parent.GetCurrentTransformAt(t, out M)) //.CloneIt(); M = new TikzMatrix(); M.m[0, 2] = offset.X; M.m[1, 2] = offset.Y; //rasterizer.RasterScale = M.m[1, 1]; Rasterizer.View.CoordinateTransform = M; Rasterizer.View.IsCartesian = !(t.IsPolar()); } else throw new Exception("In PdfOverlay: Encountered drawn item without valid coordinates"); } else if (tpi is Tikz_Path) { Tikz_Path ts = tpi as Tikz_Path; TikzMatrix M; if (IsParent) { Point curPointAtEnd; if (!ts.GetCurrentTransformAt(null, out M)) // todo M = new TikzMatrix(); // broken coords-> take unity as backup if (ts.GetAbsOffset(out curPointAtEnd, null)) { M.m[0, 2] = curPointAtEnd.X; M.m[1, 2] = curPointAtEnd.Y; } } else { if (!ts.parent.GetCurrentTransformAt(ts, out M)) M = new TikzMatrix(); //if (!ts.GetRasterTransform(out M)) // M = new TikzMatrix(); } Rasterizer.View.CoordinateTransform = M; //rasterizer.RasterOrigin = M.Transform(new Point(0, 0)); //rasterizer.RasterScale = M.m[1, 1]; Rasterizer.View.IsCartesian = !IsParent || !UsePolarCoordinates; } else Debug.WriteLine("Error in SetCorrectRaster: unsupported type");//Rasterizer.IsCartesian = true; // should not get here }