//public virtual int GetLengthBefore(TikzParseItem tpi) //{ // return ToString().Length; // //} /// <summary> /// This method triggers a TextChanged event in the root of the parse tree. /// </summary> /// <param name="sender">The node whose text was changed.</param> /// <param name="oldtext">the text of the node before the change.</param> public virtual void RaiseTextChanged(TikzParseItem sender, string oldtext) { if (parent != null) parent.RaiseTextChanged(sender, oldtext); }
/// <summary> /// Adjusts the current coordinates (seen as coordinates of relto) /// such that relto sits at p in absolute coordinates. /// The extra parameter is needed since this method is called by Tikz_Node, which /// contains a Tikz_Coord object. (In that case relto will be the Tikz_Node) /// relto is used to query, e.g., the current position in the Tikz Path. /// (Which is a parent of relto, but not of the current coordinate.) /// </summary> /// <param name="p">The new absolute (cartesian) coordinates, in cm</param> /// <param name="relto">Object with respect to which the coordinate transformation is determined</param> public void SetAbsPos(Point p, TikzParseItem relto) { if (IsBroken || type == Tikz_CoordType.Named) { // cannot change coord } else { Point relp; // will hold the new coordinates, in the current coordinate system TikzMatrix MM; if (!relto.parent.GetCurrentTransformAt(relto, out MM)) return; // broken coord trafo -> do nothing MM = MM.Inverse(); if (deco == "+" || deco == "++") { Point offset; if (relto.parent is Tikz_Controls) { Tikz_Controls par = relto.parent as Tikz_Controls; Tikz_XYItem offc = null; if (relto == par.FirstCP) offc = par.CoordBefore; else if (relto == par.LastCP) offc = par.CoordAfter; if (offc == null || !offc.GetAbsPos(out offset)) return; relp = new Point(p.X - offset.X, p.Y - offset.Y); // the desired shift, in absolute coordinates relp = MM.Transform(relp, true); } else if ((relto.parent as Tikz_Path).GetAbsOffset(out offset, relto)) { relp = new Point(p.X - offset.X, p.Y - offset.Y); // the desired shift, in absolute coordinates relp = MM.Transform(relp, true); } else { // error in determining offset -> cannot set coordinate return; } } else { relp = MM.Transform(new Point(p.X, p.Y)); // this is the target point in current coordinate system } if (type == Tikz_CoordType.Polar) { relp = Helper.CartToPolTC(relp); } uX.SetInCM(relp.X); uY.SetInCM(relp.Y); } }
/// <summary> /// Get the last item that changes the "current position" in a tikz path. /// This implememntation is not yet entirely accurate at present.... for example ... edge (v) .. does not change the current position. /// </summary> /// <param name="before">The item before which we should search.</param> /// <param name="ret">The last item that changed the current position.</param> /// <param name="VeryCurrent">Whether to return the last item changing the "very current" position (see GetAbsOffset).</param> /// <returns></returns> bool GetLastDrawnItem(TikzParseItem before, out Tikz_XYItem ret, bool VeryCurrent ) { int ind; if (before == null) ind = Children.Count; else ind = Children.IndexOf(before); //CoordTrafoInBetween = new TikzMatrix(); for (int i = ind - 1; i >= 0; i--) { if (Children[i] is Tikz_Coord) { Tikz_Coord tc = Children[i] as Tikz_Coord; if (tc.type == Tikz_CoordType.Named || tc.deco != "+" || VeryCurrent) { ret = tc; return true; } } else if (Children[i] is Tikz_Arc) { ret = Children[i] as Tikz_Arc; return true; } //else if (Children[i] is Tikz_Options) //{ // CoordTrafoInBetween = (Children[i] as Tikz_Options).GetTransform() * CoordTrafoInBetween; //} else if (Children[i] is Tikz_Path) { Tikz_Path tp = (Children[i] as Tikz_Path); Tikz_XYItem tpi; //TikzMatrix M; // not used here bool lret = tp.GetLastDrawnItem(null, out tpi, VeryCurrent); if (lret) { ret = tpi; return true; } } } // nothing found -> look in parent if (this.parent is Tikz_Path) { Tikz_Path tparent = parent as Tikz_Path; Tikz_XYItem tpi; if (tparent.GetLastDrawnItem(this, out tpi, VeryCurrent)) { ret = tpi; return true; } } // if we come here, nothing has been found... ret = null; return false; }
public bool IsChildOfOrSelf(TikzParseItem tpi) { return (this == tpi) || Ancestors.Contains(tpi); }
public override void RaiseTextChanged(TikzParseItem sender, string oldtext) { if (TextChanged != null) TextChanged(this, new ParseTreeTextChangedEventArgs() { ChangedItem=sender, OldText=oldtext }); //base.RaiseTextChanged(sender, oldtext); }
/// <summary> /// Gets the offset, i.e., the current drawing position at some /// position along the path. (in absolute Cartesian coordinates) /// This is used to determine the absolute position of items specified with relative /// coordinates like +(1,1). /// /// Note that in Tikz two offsets are relevant: /// Example: /// \draw (0,0) +(1,1) node {1} +(3,3) -- (5,5); /// Node 1 is placed at +(1,1), the "very current" position. /// The coordinate +(3,3) is taken relative to the "current position", i.e., (0,0). /// </summary> /// <param name="tpi">The item just before which the current drawing position is to be determined.</param> /// <param name="VeryCurrent">Whether to "very current" position.</param> /// <returns>True, if offset could be determined, false otherwise.</returns> public bool GetAbsOffset(out Point ret, TikzParseItem tpi, bool VeryCurrent = false) { Tikz_XYItem tcret; if (GetLastDrawnItem(tpi, out tcret, VeryCurrent)) { // last drawn item exists TikzMatrix M2, M1; if (!GetCurrentTransformAt(tpi, out M2) || !tcret.parent.GetCurrentTransformAt(tcret, out M1)) { ret = new Point(0, 0); return false; } Point p1; if (tcret.GetAbsPos(out p1)) { // p1 = M2 * orig point; offset = M1 * orig point (I guess) => offset = M1 * I(M2) * p1 ret = (M2 * (M1.Inverse())).Transform(p1); return true; } else { ret = new Point(0, 0); return false; } } else { // no item was drawn before.... take origin (...after coord transform) TikzMatrix M; if (!GetCurrentTransformAt(tpi, out M)) { ret = new Point(0, 0); return false; } ret = M.Transform(new Point(0, 0)); return true; } /*int ind = Children.IndexOf(tpi); Tikz_Coord previous = null; for (int i = ind - 1; i >= 0; i--) { if (Children[i] is Tikz_Coord) { Tikz_Coord tc = Children[i] as Tikz_Coord; if (tc.type == Tikz_CoordType.Named || tc.deco != "+") { previous = tc; break; } } } if (previous == null) return GetCurrentTransformAt(tpi).Transform(new Point(0,0)); else return previous.GetAbsPos(); */ }
/* 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 }
public void InsertChildAt(TikzParseItem tpi, int position) { tpi.parent = this; Children.Insert(position, tpi); // raise event RaiseTextChanged(tpi, ""); RaiseParseTreeModified(new ParseTreeModifiedEventArgs() { AffectedItem = tpi, Type = ParseTreeModifiedType.Insert }); }
/// <summary> /// Removes a child /// </summary> /// <param name="tpi"></param> /// <param name="InsertAsFirst"></param> public void RemoveChild(TikzParseItem tpi) { int startpos = tpi.StartPosition(); string oldtext = tpi.ToString(); tpi.parent = null; Children.Remove(tpi); // raise event RaiseTextChanged(new DummyTikzParseItem(startpos), oldtext); RaiseParseTreeModified(new ParseTreeModifiedEventArgs() { AffectedItem = tpi, Type = ParseTreeModifiedType.Remove }); }
/// <summary> /// This should be called instead of adding nodes to Children directly /// </summary> /// <param name="tpi"></param> public void AddChild(TikzParseItem tpi, bool InsertAsFirst=false) { tpi.parent = this; if (InsertAsFirst) Children.Insert(0, tpi); else Children.Add(tpi); // raise event RaiseTextChanged(tpi, ""); RaiseParseTreeModified(new ParseTreeModifiedEventArgs() { AffectedItem = tpi, Type = ParseTreeModifiedType.Insert }); }
IEnumerable<OverlayShapeVM> CreateOverlayShapesFromItem(TikzParseItem tpi) { var ret = new List<OverlayShapeVM>(); if (tpi is Tikz_Scope) { OverlayScope os = new OverlayScope(); //os.pol = this; os.tikzitem = tpi as Tikz_Scope; // add child shapes os.children.AddRange( (tpi as TikzContainerParseItem).Children.SelectMany( child => CreateOverlayShapesFromItem(child) ) ); //foreach (TikzParseItem t in (tpi as TikzContainerParseItem).Children) // DrawObject(t, os.children); // don't draw scopes with no drawable children // (we don't know where to render them) if (os.children.Count > 0) { ret.Add(os); os.AdjustPosition(TikzToScreen); } } else if (tpi is TikzContainerParseItem) { ret.AddRange( (tpi as TikzContainerParseItem).Children.SelectMany( child => CreateOverlayShapesFromItem(child) ) ); } else if (tpi is Tikz_XYItem) { if ((tpi as Tikz_XYItem).HasEditableCoordinate()) { OverlayNode el; if (tpi.parent is Tikz_Controls) el = new OverlayControlPoint(); // control points for Bezier curves else el = new OverlayNode(); //el.pol = this; el.tikzitem = tpi as Tikz_XYItem; el.AdjustPosition(TikzToScreen); // add tooltip if (ParseTree != null) { Tikz_Node nref = TikzParseTreeHelper.GetReferenceableNode(tpi as Tikz_XYItem, ParseTree.GetTikzPicture()); if (nref != null && !String.IsNullOrWhiteSpace(nref.name)) { el.ToolTip = nref.name; } } ////canvas1.Children.Add(el); ret.Add(el); //bbg.Add(new Rect(Canvas.GetLeft(el), Canvas.GetTop(el), el.Width, el.Height)); } } else if (tpi is Tikz_Path) { } return ret; }
/// <summary> /// Adds a single parseitem to the display tree and redraws. /// This is called by tools adding something to the parsetree to refresh the overlay /// without redrawing it completely. /// </summary> /// <param name="tpi">The parseitem to add.</param> public void AddToDisplayTree(TikzParseItem tpi) { List<OverlayShape> l = new List<OverlayShape>(); DrawObject(tpi, l); if (CurEditing == null) { //do not redraw if there is nothing to show. if (TopLevelItems == null) RedrawObjects(); TopLevelItems.AddRange(l); } else { CurEditing.children.AddRange(l); } AdjustPositions(); BindControlPointsToOrigins(); }
/// <summary> /// Gets the absolute position. For the significance of relto, see SetAbsPos() /// </summary> /// <param name="relto"></param> /// <param name="OnlyOffset">Only the coordinate offset is returned. (This is used to determine the raster offset.)</param> /// <returns>The position in the coordinates of the ancestral Tikz_Picture, or (0,0) in case of failure.</returns> public bool GetAbsPos(out Point ret, TikzParseItem relto, bool OnlyOffset=false) { if (IsBroken || type == Tikz_CoordType.Invalid) // cannot determine coordinates { ret = new Point(0,0); return false; } Point offset = new Point(0, 0); if (type == Tikz_CoordType.Named) { if (relto.parent == null) { // node name not find in node list (either error or not parsed) ret = new Point(0, 0); return false; } // try to get referenced node... if (nameref == "") // empty reference means that we reference the current position (treat as +(0,0)) { // determine current position if (relto.parent is Tikz_Path) { if (!(relto.parent as Tikz_Path).GetAbsOffset(out ret, relto)) { // error in determining offset -> cannot determine coordinates ret = new Point(0, 0); return false; } else return true; // success } else { // couldn't get offset, because the parent is some container I don't know -> fail ret = new Point(0, 0); return false; } } Tikz_Node t = relto.parent.GetNodeByName(nameref); if (t == null) { ret = new Point(0, 0); return false; } else { // Tikz allows decorations (+, ++) in front of named coordinates, but not nodes (!!!) // so we have to take care of this case separately /*if ( (deco == "+" || deco == "++") && t.parent.starttag.Trim() == "\\coordinate") { if (relto.parent is Tikz_Path) { if (!(relto.parent as Tikz_Path).GetAbsOffset(out offset, relto)) { // error in determining offset -> cannot determine coordinates ret = new Point(0, 0); return false; } } if (t.GetAbsPos(out ret)) { ret = new Point(ret.X + offset.X, ret.Y + offset.Y); } else return false; } else*/ return t.GetAbsPos(out ret); } } else if (type == Tikz_CoordType.Cartesian || type == Tikz_CoordType.Polar) { // determine offset if there is a decoration... // for this we have to ask the parent Tikz Path what the current position is if (deco == "+" || deco == "++") { // determine offset if (relto.parent is Tikz_Path) { if (!(relto.parent as Tikz_Path).GetAbsOffset(out offset, relto)) { // error in determining offset -> cannot determine coordinates ret = new Point(0, 0); return false; } } else if (relto.parent is Tikz_Controls) { Tikz_Controls par = relto.parent as Tikz_Controls; Tikz_XYItem offc = null; if (relto == par.FirstCP) offc = par.CoordBefore; else if (relto == par.LastCP) offc = par.CoordAfter; if (offc == null || !offc.GetAbsPos(out offset)) { ret = new Point(0, 0); return false; } } else { // not supported } Point relpos = new Point(uX.GetInCM(), uY.GetInCM()); if (type == Tikz_CoordType.Polar) relpos = Helper.PolToCartTC(relpos); if (relto.parent != null) { TikzMatrix M; if (!relto.parent.GetCurrentTransformAt(relto, out M)) { ret = new Point(0, 0); return false; } relpos = M.Transform(relpos, true); } if (OnlyOffset) { ret = offset; return true; } else { ret = new Point(offset.X + relpos.X, offset.Y + relpos.Y); return true; } } // standard coordinate (not relative etc.) Point p = new Point(uX.GetInCM(), uY.GetInCM()); if (type == Tikz_CoordType.Polar) p = Helper.PolToCartTC(p); if (relto.parent == null) { if (OnlyOffset) { ret = new Point(0, 0); } else { ret = p; } return true; } else { TikzMatrix M; if (!relto.parent.GetCurrentTransformAt(relto, out M)) { ret = new Point(0, 0); return false; } //Point pret; if (OnlyOffset) { ret = M.Transform(new Point(0, 0)); } else { ret = M.Transform(p); } return true; } } else // if (type == ...) { // Unsupported type ret = new Point(0, 0); return false; } }
public int GetLengthBefore(TikzParseItem tpi) { int pos = 0; if (parent != null) pos = parent.GetLengthBefore(this); pos += starttag.Length; //if (options != null) // pos += options.ToString().Length; foreach (TikzParseItem t in Children) { if (t == tpi) break; else pos += t.ToString().Length; } return pos; }
private void pdfOverlay1_OnModified(TikzParseItem sender, string oldtext) { // update code int InsertAt = sender.StartPosition(); if (InsertAt > txtCode.Text.Length) { MainWindow.AddStatusLine("Trying to insert code \"" + sender.ToString().Replace(Environment.NewLine, "<NEWLINE>") + "\" to position " + sender.StartPosition() + " but document has only " + txtCode.Text.Length + " characters." + " Inserting code at end of document instead. Code does probably not compile now. Please correct or choose undo.", true); InsertAt = txtCode.Text.Length; } txtCode.Document.Replace(InsertAt, oldtext.Length, sender.ToString()); }
/// <summary> /// Draws the TikzParseItem tpi, if it is drawn, or its children, if they can be drawn, /// or grandchildren etc..., and adds the drawn items to bag. /// </summary> /// <param name="tpi"></param> /// <param name="bag"></param> public void DrawObject(TikzParseItem tpi, List<OverlayShape> bag) { //BBGatherer bbg = new BBGatherer(); if (bag == null) bag = new List<OverlayShape>(); // dummy, it is not used if (tpi is Tikz_Scope) { OverlayScope os = new OverlayScope(ShapeFactory.NewScopeView()); os.pol = this; os.tikzitem = tpi as Tikz_Scope; foreach (TikzParseItem t in (tpi as TikzContainerParseItem).Children) DrawObject(t, os.children); // don't draw scopes with no drawable children // (we don't know where to render them) if (os.children.Count > 0) { bag.Add(os); os.AdjustPosition(Resolution); ////canvas1.Children.Add(os); } } else if (tpi is TikzContainerParseItem) { foreach (TikzParseItem t in (tpi as TikzContainerParseItem).Children) DrawObject(t, bag); } if (tpi is Tikz_XYItem) { if ((tpi as Tikz_XYItem).HasEditableCoordinate()) { OverlayNode el; if (tpi.parent is Tikz_Controls) el = new OverlayControlPoint(ShapeFactory.NewCPView()); // control points for Bezier curves else el = new OverlayNode(ShapeFactory.NewNodeView()); el.pol = this; el.tikzitem = tpi as Tikz_XYItem; //Ellipse el = new Ellipse(); //el.Stroke = Brushes.Red; el.AdjustPosition(Resolution); // add tooltip Tikz_Node nref = TikzParseTreeHelper.GetReferenceableNode(tpi as Tikz_XYItem, ParseTree.GetTikzPicture()); if (nref != null && nref.name != "") { el.View.SetToolTip(nref.name); } ////canvas1.Children.Add(el); bag.Add(el); //bbg.Add(new Rect(Canvas.GetLeft(el), Canvas.GetTop(el), el.Width, el.Height)); } } else if (tpi is Tikz_Path) { //could this be a possibility to show edges and provide backward search? //there are many possibility for draw commands. here we /* string simpleEdge_RegexString = @"[ \t\s]*\\draw.*\((?<start>.*)\).*\((?<end>.*)\).*"; Regex BB_Regex = new Regex(simpleEdge_RegexString); Match m = BB_Regex.Match(tpi.ToString()); if (m.Success == true) { //we just found a LaTex draw cmd, e.g.: \draw[default_edge] (v91) to (v99); //get both nodes Tikz_Node StartNode = tpi.parent.GetNodeByName(m.Groups[1].Value); Tikz_Node EndNode = tpi.parent.GetNodeByName(m.Groups[2].Value); if (StartNode != null && EndNode != null) { //and determine the position in between both nodes Point start, end; if (StartNode.GetAbsPos() double x = (StartNode.GetAbsPos().X + EndNode.GetAbsPos().X) / 2; double y = (StartNode.GetAbsPos().Y + EndNode.GetAbsPos().Y) / 2; //draw an arrow at this pos. //(new Point(x, y)); //and when clicked, jump to AvalonEdit at position tpi.StartPosition } } */ } }