From a590df5035bb791a363ca7bd38a06e2c93297908 Mon Sep 17 00:00:00 2001 From: dexyfex Date: Sun, 25 Feb 2018 23:30:29 +1100 Subject: [PATCH] Snap to ground and grid options --- CodeWalker.Core/Utils/Vectors.cs | 5 ++ Project/UndoStep.cs | 2 +- Utils/MapUtils.cs | 2 +- World/Widget.cs | 4 +- WorldForm.Designer.cs | 115 +++++++++++++++++++++++--- WorldForm.cs | 138 ++++++++++++++++++++++++++++++- WorldForm.resx | 37 +++++++++ 7 files changed, 282 insertions(+), 21 deletions(-) diff --git a/CodeWalker.Core/Utils/Vectors.cs b/CodeWalker.Core/Utils/Vectors.cs index e0418f7..b953850 100644 --- a/CodeWalker.Core/Utils/Vectors.cs +++ b/CodeWalker.Core/Utils/Vectors.cs @@ -16,6 +16,11 @@ namespace CodeWalker } + public static Vector3 Round(this Vector3 v) + { + return new Vector3((float)Math.Round(v.X), (float)Math.Round(v.Y), (float)Math.Round(v.Z)); + } + public static Vector4 Floor(this Vector4 v) { return new Vector4((float)Math.Floor(v.X), (float)Math.Floor(v.Y), (float)Math.Floor(v.Z), (float)Math.Floor(v.W)); diff --git a/Project/UndoStep.cs b/Project/UndoStep.cs index 963216b..3c1dd6d 100644 --- a/Project/UndoStep.cs +++ b/Project/UndoStep.cs @@ -47,7 +47,7 @@ namespace CodeWalker.Project for (int i = 0; i < Items.Length; i++) { var refpos = Items[i].WidgetPosition; - Items[i].SetPosition(refpos + dp, refpos, false); + Items[i].SetPosition(refpos + dp, false); } sel.MultipleSelectionCenter = p; //center used for widget pos... diff --git a/Utils/MapUtils.cs b/Utils/MapUtils.cs index a54ec36..a987979 100644 --- a/Utils/MapUtils.cs +++ b/Utils/MapUtils.cs @@ -640,7 +640,7 @@ namespace CodeWalker - public void SetPosition(Vector3 newpos, Vector3 oldpos, bool editPivot) + public void SetPosition(Vector3 newpos, bool editPivot) { if (MultipleSelection) { diff --git a/World/Widget.cs b/World/Widget.cs index 0a404f8..d98fb65 100644 --- a/World/Widget.cs +++ b/World/Widget.cs @@ -263,8 +263,8 @@ namespace CodeWalker.World public Vector3 DraggedAxisSideDir { get; set; } public Vector3 DragStartPosition { get; set; } public bool IsDragging { get; set; } - private bool WasDragging = false; - private Vector3 DragStartVec; //projected onto the plane/axis being dragged + public bool WasDragging = false; + public Vector3 DragStartVec; //projected onto the plane/axis being dragged public float Size { get; set; } = 90.0f; diff --git a/WorldForm.Designer.cs b/WorldForm.Designer.cs index c824bda..18ece1b 100644 --- a/WorldForm.Designer.cs +++ b/WorldForm.Designer.cs @@ -278,6 +278,12 @@ namespace CodeWalker this.ToolbarCameraMapViewButton = new System.Windows.Forms.ToolStripMenuItem(); this.ToolbarCameraOrthographicButton = new System.Windows.Forms.ToolStripMenuItem(); this.ToolbarPanel = new System.Windows.Forms.Panel(); + this.ToolbarSnapButton = new CodeWalker.WinForms.ToolStripSplitButtonFix(); + this.ToolbarSnapToGroundButton = new System.Windows.Forms.ToolStripMenuItem(); + this.ToolbarSnapToGridButton = new System.Windows.Forms.ToolStripMenuItem(); + this.ToolbarSnapToGroundGridButton = new System.Windows.Forms.ToolStripMenuItem(); + this.label26 = new System.Windows.Forms.Label(); + this.SnapGridSizeUpDown = new System.Windows.Forms.NumericUpDown(); this.StatusStrip.SuspendLayout(); this.ToolsPanel.SuspendLayout(); this.ToolsTabControl.SuspendLayout(); @@ -318,6 +324,7 @@ namespace CodeWalker this.ToolsMenu.SuspendLayout(); this.Toolbar.SuspendLayout(); this.ToolbarPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.SnapGridSizeUpDown)).BeginInit(); this.SuspendLayout(); // // StatusStrip @@ -1747,6 +1754,8 @@ namespace CodeWalker // // tabPage9 // + this.tabPage9.Controls.Add(this.SnapGridSizeUpDown); + this.tabPage9.Controls.Add(this.label26); this.tabPage9.Controls.Add(this.SkeletonsCheckBox); this.tabPage9.Controls.Add(this.AudioOuterBoundsCheckBox); this.tabPage9.Controls.Add(this.PopZonesCheckBox); @@ -1782,7 +1791,7 @@ namespace CodeWalker this.SkeletonsCheckBox.Location = new System.Drawing.Point(10, 411); this.SkeletonsCheckBox.Name = "SkeletonsCheckBox"; this.SkeletonsCheckBox.Size = new System.Drawing.Size(101, 17); - this.SkeletonsCheckBox.TabIndex = 53; + this.SkeletonsCheckBox.TabIndex = 55; this.SkeletonsCheckBox.Text = "Show skeletons"; this.SkeletonsCheckBox.UseVisualStyleBackColor = true; this.SkeletonsCheckBox.CheckedChanged += new System.EventHandler(this.SkeletonsCheckBox_CheckedChanged); @@ -1795,7 +1804,7 @@ namespace CodeWalker this.AudioOuterBoundsCheckBox.Location = new System.Drawing.Point(10, 457); this.AudioOuterBoundsCheckBox.Name = "AudioOuterBoundsCheckBox"; this.AudioOuterBoundsCheckBox.Size = new System.Drawing.Size(147, 17); - this.AudioOuterBoundsCheckBox.TabIndex = 55; + this.AudioOuterBoundsCheckBox.TabIndex = 57; this.AudioOuterBoundsCheckBox.Text = "Show audio outer bounds"; this.AudioOuterBoundsCheckBox.UseVisualStyleBackColor = true; this.AudioOuterBoundsCheckBox.CheckedChanged += new System.EventHandler(this.AudioOuterBoundsCheckBox_CheckedChanged); @@ -1806,7 +1815,7 @@ namespace CodeWalker this.PopZonesCheckBox.Location = new System.Drawing.Point(10, 388); this.PopZonesCheckBox.Name = "PopZonesCheckBox"; this.PopZonesCheckBox.Size = new System.Drawing.Size(136, 17); - this.PopZonesCheckBox.TabIndex = 52; + this.PopZonesCheckBox.TabIndex = 54; this.PopZonesCheckBox.Text = "Show population zones"; this.PopZonesCheckBox.UseVisualStyleBackColor = true; this.PopZonesCheckBox.CheckedChanged += new System.EventHandler(this.PopZonesCheckBox_CheckedChanged); @@ -1817,7 +1826,7 @@ namespace CodeWalker this.NavMeshesCheckBox.Location = new System.Drawing.Point(10, 365); this.NavMeshesCheckBox.Name = "NavMeshesCheckBox"; this.NavMeshesCheckBox.Size = new System.Drawing.Size(113, 17); - this.NavMeshesCheckBox.TabIndex = 51; + this.NavMeshesCheckBox.TabIndex = 53; this.NavMeshesCheckBox.Text = "Show nav meshes"; this.NavMeshesCheckBox.UseVisualStyleBackColor = true; this.NavMeshesCheckBox.CheckedChanged += new System.EventHandler(this.NavMeshesCheckBox_CheckedChanged); @@ -1828,7 +1837,7 @@ namespace CodeWalker this.TrainPathsCheckBox.Location = new System.Drawing.Point(10, 342); this.TrainPathsCheckBox.Name = "TrainPathsCheckBox"; this.TrainPathsCheckBox.Size = new System.Drawing.Size(105, 17); - this.TrainPathsCheckBox.TabIndex = 50; + this.TrainPathsCheckBox.TabIndex = 52; this.TrainPathsCheckBox.Text = "Show train paths"; this.TrainPathsCheckBox.UseVisualStyleBackColor = true; this.TrainPathsCheckBox.CheckedChanged += new System.EventHandler(this.TrainPathsCheckBox_CheckedChanged); @@ -1839,7 +1848,7 @@ namespace CodeWalker this.PathsDepthClipCheckBox.Location = new System.Drawing.Point(10, 434); this.PathsDepthClipCheckBox.Name = "PathsDepthClipCheckBox"; this.PathsDepthClipCheckBox.Size = new System.Drawing.Size(102, 17); - this.PathsDepthClipCheckBox.TabIndex = 54; + this.PathsDepthClipCheckBox.TabIndex = 56; this.PathsDepthClipCheckBox.Text = "Paths depth clip"; this.PathsDepthClipCheckBox.UseVisualStyleBackColor = true; this.PathsDepthClipCheckBox.CheckedChanged += new System.EventHandler(this.PathsDepthClipCheckBox_CheckedChanged); @@ -1852,7 +1861,7 @@ namespace CodeWalker this.PathBoundsCheckBox.Location = new System.Drawing.Point(98, 319); this.PathBoundsCheckBox.Name = "PathBoundsCheckBox"; this.PathBoundsCheckBox.Size = new System.Drawing.Size(86, 17); - this.PathBoundsCheckBox.TabIndex = 49; + this.PathBoundsCheckBox.TabIndex = 51; this.PathBoundsCheckBox.Text = "Path bounds"; this.PathBoundsCheckBox.UseVisualStyleBackColor = true; this.PathBoundsCheckBox.CheckedChanged += new System.EventHandler(this.PathBoundsCheckBox_CheckedChanged); @@ -1949,7 +1958,7 @@ namespace CodeWalker this.PathsCheckBox.Location = new System.Drawing.Point(10, 319); this.PathsCheckBox.Name = "PathsCheckBox"; this.PathsCheckBox.Size = new System.Drawing.Size(82, 17); - this.PathsCheckBox.TabIndex = 48; + this.PathsCheckBox.TabIndex = 50; this.PathsCheckBox.Text = "Show paths"; this.PathsCheckBox.UseVisualStyleBackColor = true; this.PathsCheckBox.CheckedChanged += new System.EventHandler(this.PathsCheckBox_CheckedChanged); @@ -2615,6 +2624,7 @@ namespace CodeWalker this.ToolbarRotateButton, this.ToolbarScaleButton, this.ToolbarTransformSpaceButton, + this.ToolbarSnapButton, this.toolStripSeparator2, this.ToolbarUndoButton, this.ToolbarRedoButton, @@ -2631,7 +2641,7 @@ namespace CodeWalker this.ToolbarCameraModeButton}); this.Toolbar.Location = new System.Drawing.Point(1, 0); this.Toolbar.Name = "Toolbar"; - this.Toolbar.Size = new System.Drawing.Size(522, 25); + this.Toolbar.Size = new System.Drawing.Size(554, 25); this.Toolbar.TabIndex = 6; this.Toolbar.Text = "toolStrip1"; // @@ -2793,7 +2803,7 @@ namespace CodeWalker this.ToolbarSelectButton.ImageTransparentColor = System.Drawing.Color.Magenta; this.ToolbarSelectButton.Name = "ToolbarSelectButton"; this.ToolbarSelectButton.Size = new System.Drawing.Size(32, 22); - this.ToolbarSelectButton.Text = "toolStripSplitButton1"; + this.ToolbarSelectButton.Text = "Select objects / Exit edit mode"; this.ToolbarSelectButton.ToolTipText = "Select objects / Exit edit mode (C, Q)"; this.ToolbarSelectButton.ButtonClick += new System.EventHandler(this.ToolbarSelectButton_ButtonClick); // @@ -2961,7 +2971,7 @@ namespace CodeWalker this.ToolbarObjectSpaceButton.CheckState = System.Windows.Forms.CheckState.Checked; this.ToolbarObjectSpaceButton.Image = ((System.Drawing.Image)(resources.GetObject("ToolbarObjectSpaceButton.Image"))); this.ToolbarObjectSpaceButton.Name = "ToolbarObjectSpaceButton"; - this.ToolbarObjectSpaceButton.Size = new System.Drawing.Size(142, 22); + this.ToolbarObjectSpaceButton.Size = new System.Drawing.Size(152, 22); this.ToolbarObjectSpaceButton.Text = "Object space"; this.ToolbarObjectSpaceButton.Click += new System.EventHandler(this.ToolbarObjectSpaceButton_Click); // @@ -2969,7 +2979,7 @@ namespace CodeWalker // this.ToolbarWorldSpaceButton.Image = ((System.Drawing.Image)(resources.GetObject("ToolbarWorldSpaceButton.Image"))); this.ToolbarWorldSpaceButton.Name = "ToolbarWorldSpaceButton"; - this.ToolbarWorldSpaceButton.Size = new System.Drawing.Size(142, 22); + this.ToolbarWorldSpaceButton.Size = new System.Drawing.Size(152, 22); this.ToolbarWorldSpaceButton.Text = "World space"; this.ToolbarWorldSpaceButton.Click += new System.EventHandler(this.ToolbarWorldSpaceButton_Click); // @@ -3152,10 +3162,82 @@ namespace CodeWalker this.ToolbarPanel.Controls.Add(this.Toolbar); this.ToolbarPanel.Location = new System.Drawing.Point(12, 12); this.ToolbarPanel.Name = "ToolbarPanel"; - this.ToolbarPanel.Size = new System.Drawing.Size(525, 26); + this.ToolbarPanel.Size = new System.Drawing.Size(557, 26); this.ToolbarPanel.TabIndex = 7; this.ToolbarPanel.Visible = false; // + // ToolbarSnapButton + // + this.ToolbarSnapButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.ToolbarSnapButton.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.ToolbarSnapToGroundButton, + this.ToolbarSnapToGridButton, + this.ToolbarSnapToGroundGridButton}); + this.ToolbarSnapButton.Image = ((System.Drawing.Image)(resources.GetObject("ToolbarSnapButton.Image"))); + this.ToolbarSnapButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.ToolbarSnapButton.Name = "ToolbarSnapButton"; + this.ToolbarSnapButton.Size = new System.Drawing.Size(32, 22); + this.ToolbarSnapButton.Text = "Snap to Ground"; + this.ToolbarSnapButton.ToolTipText = "Snap to Ground"; + this.ToolbarSnapButton.ButtonClick += new System.EventHandler(this.ToolbarSnapButton_ButtonClick); + // + // ToolbarSnapToGroundButton + // + this.ToolbarSnapToGroundButton.Image = ((System.Drawing.Image)(resources.GetObject("ToolbarSnapToGroundButton.Image"))); + this.ToolbarSnapToGroundButton.Name = "ToolbarSnapToGroundButton"; + this.ToolbarSnapToGroundButton.Size = new System.Drawing.Size(205, 22); + this.ToolbarSnapToGroundButton.Text = "Snap to Ground"; + this.ToolbarSnapToGroundButton.Click += new System.EventHandler(this.ToolbarSnapToGroundButton_Click); + // + // ToolbarSnapToGridButton + // + this.ToolbarSnapToGridButton.Image = ((System.Drawing.Image)(resources.GetObject("ToolbarSnapToGridButton.Image"))); + this.ToolbarSnapToGridButton.Name = "ToolbarSnapToGridButton"; + this.ToolbarSnapToGridButton.Size = new System.Drawing.Size(205, 22); + this.ToolbarSnapToGridButton.Text = "Snap to Grid"; + this.ToolbarSnapToGridButton.Click += new System.EventHandler(this.ToolbarSnapToGridButton_Click); + // + // ToolbarSnapToGroundGridButton + // + this.ToolbarSnapToGroundGridButton.Image = ((System.Drawing.Image)(resources.GetObject("ToolbarSnapToGroundGridButton.Image"))); + this.ToolbarSnapToGroundGridButton.Name = "ToolbarSnapToGroundGridButton"; + this.ToolbarSnapToGroundGridButton.Size = new System.Drawing.Size(205, 22); + this.ToolbarSnapToGroundGridButton.Text = "Snap to Grid and Ground"; + this.ToolbarSnapToGroundGridButton.Click += new System.EventHandler(this.ToolbarSnapToGroundGridButton_Click); + // + // label26 + // + this.label26.AutoSize = true; + this.label26.Location = new System.Drawing.Point(4, 293); + this.label26.Name = "label26"; + this.label26.Size = new System.Drawing.Size(76, 13); + this.label26.TabIndex = 48; + this.label26.Text = "Snap grid size:"; + // + // SnapGridSizeUpDown + // + this.SnapGridSizeUpDown.DecimalPlaces = 2; + this.SnapGridSizeUpDown.Location = new System.Drawing.Point(86, 291); + this.SnapGridSizeUpDown.Maximum = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + this.SnapGridSizeUpDown.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 131072}); + this.SnapGridSizeUpDown.Name = "SnapGridSizeUpDown"; + this.SnapGridSizeUpDown.Size = new System.Drawing.Size(108, 20); + this.SnapGridSizeUpDown.TabIndex = 49; + this.SnapGridSizeUpDown.Value = new decimal(new int[] { + 100, + 0, + 0, + 131072}); + this.SnapGridSizeUpDown.ValueChanged += new System.EventHandler(this.SnapGridSizeUpDown_ValueChanged); + // // WorldForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -3236,6 +3318,7 @@ namespace CodeWalker this.Toolbar.PerformLayout(); this.ToolbarPanel.ResumeLayout(false); this.ToolbarPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.SnapGridSizeUpDown)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -3489,5 +3572,11 @@ namespace CodeWalker private System.Windows.Forms.ToolStripMenuItem ToolbarSelectAudioButton; private System.Windows.Forms.CheckBox AudioOuterBoundsCheckBox; private System.Windows.Forms.CheckBox SkeletonsCheckBox; + private ToolStripSplitButtonFix ToolbarSnapButton; + private System.Windows.Forms.ToolStripMenuItem ToolbarSnapToGroundButton; + private System.Windows.Forms.ToolStripMenuItem ToolbarSnapToGridButton; + private System.Windows.Forms.ToolStripMenuItem ToolbarSnapToGroundGridButton; + private System.Windows.Forms.NumericUpDown SnapGridSizeUpDown; + private System.Windows.Forms.Label label26; } } \ No newline at end of file diff --git a/WorldForm.cs b/WorldForm.cs index 1cbc877..d016e75 100644 --- a/WorldForm.cs +++ b/WorldForm.cs @@ -171,6 +171,10 @@ namespace CodeWalker Quaternion UndoStartRotation; Vector3 UndoStartScale; + WorldSnapMode SnapMode = WorldSnapMode.None; + WorldSnapMode SnapModePrev = WorldSnapMode.Ground;//also the default snap mode + float SnapGridSize = 1.0f; + YmapEntityDef CopiedEntity = null; YmapCarGen CopiedCarGen = null; YndNode CopiedPathNode = null; @@ -1461,9 +1465,52 @@ namespace CodeWalker Widget.Update(camera); } + + + private Vector3 GetGroundPoint(Vector3 p) + { + float uplimit = 3.0f; + float downlimit = 20.0f; + Ray ray = new Ray(p, new Vector3(0, 0, -1.0f)); + ray.Position.Z += 0.1f; + SpaceRayIntersectResult hit = space.RayIntersect(ray, downlimit); + if (hit.Hit) + { + return hit.Position; + } + ray.Position.Z += uplimit; + hit = space.RayIntersect(ray, downlimit); + if (hit.Hit) + { + return hit.Position; + } + return p; + } + private Vector3 SnapPosition(Vector3 p) + { + Vector3 gpos = (p / SnapGridSize).Round() * SnapGridSize; + switch (SnapMode) + { + case WorldSnapMode.Grid: + p = gpos; + break; + case WorldSnapMode.Ground: + p = GetGroundPoint(p); + break; + case WorldSnapMode.Hybrid: + p = GetGroundPoint(gpos); + break; + } + return p; + } + + private void Widget_OnPositionChange(Vector3 newpos, Vector3 oldpos) { //called during UpdateWidgets() + + newpos = SnapPosition(newpos); + if (newpos == oldpos) return; if (SelectedItem.MultipleSelection) @@ -1473,18 +1520,19 @@ namespace CodeWalker } else { - var dpos = newpos - oldpos; + var dpos = newpos - SelectedItem.MultipleSelectionCenter;// oldpos; + if (dpos == Vector3.Zero) return; //nothing moved.. (probably due to snap) for (int i = 0; i < SelectedItems.Count; i++) { var refpos = SelectedItems[i].WidgetPosition; - SelectedItems[i].SetPosition(refpos + dpos, refpos, false); + SelectedItems[i].SetPosition(refpos + dpos, false); } SelectedItem.MultipleSelectionCenter = newpos; } } else { - SelectedItem.SetPosition(newpos, oldpos, EditEntityPivot); + SelectedItem.SetPosition(newpos, EditEntityPivot); } if (ProjectForm != null) { @@ -5317,6 +5365,49 @@ namespace CodeWalker } + private void SetSnapMode(WorldSnapMode mode) + { + foreach (var child in ToolbarSnapButton.DropDownItems) + { + var childi = child as ToolStripMenuItem; + if (childi != null) + { + childi.Checked = false; + } + } + + ToolbarSnapButton.Checked = (mode != WorldSnapMode.None); + + ToolStripMenuItem selItem = null; + + switch (mode) + { + case WorldSnapMode.Ground: + selItem = ToolbarSnapToGroundButton; + break; + case WorldSnapMode.Grid: + selItem = ToolbarSnapToGridButton; + break; + case WorldSnapMode.Hybrid: + selItem = ToolbarSnapToGroundGridButton; + break; + } + + if (selItem != null) + { + selItem.Checked = true; + ToolbarSnapButton.Image = selItem.Image; + ToolbarSnapButton.Text = selItem.Text; + ToolbarSnapButton.ToolTipText = selItem.ToolTipText; + } + + if (mode != WorldSnapMode.None) + { + SnapModePrev = mode; + } + SnapMode = mode; + } + private void SetCameraMode(string modestr) { @@ -5508,6 +5599,7 @@ namespace CodeWalker { MarkUndoEnd(GrabbedWidget); GrabbedWidget.IsDragging = false; + GrabbedWidget.Position = SelectedItem.WidgetPosition;//in case of any snapping, make sure widget is in correct position at the end GrabbedWidget = null; } if ((e.Location == MouseDownPoint) && (MousedMarker == null)) @@ -6867,6 +6959,33 @@ namespace CodeWalker SetWidgetSpace("World space"); } + private void ToolbarSnapButton_ButtonClick(object sender, EventArgs e) + { + if (SnapMode == WorldSnapMode.None) + { + SetSnapMode(SnapModePrev); + } + else + { + SetSnapMode(WorldSnapMode.None); + } + } + + private void ToolbarSnapToGroundButton_Click(object sender, EventArgs e) + { + SetSnapMode(WorldSnapMode.Ground); + } + + private void ToolbarSnapToGridButton_Click(object sender, EventArgs e) + { + SetSnapMode(WorldSnapMode.Grid); + } + + private void ToolbarSnapToGroundGridButton_Click(object sender, EventArgs e) + { + SetSnapMode(WorldSnapMode.Hybrid); + } + private void ToolbarUndoButton_ButtonClick(object sender, EventArgs e) { Undo(); @@ -7040,6 +7159,11 @@ namespace CodeWalker { e.Handled = true; } + + private void SnapGridSizeUpDown_ValueChanged(object sender, EventArgs e) + { + SnapGridSize = (float)SnapGridSizeUpDown.Value; + } } @@ -7053,6 +7177,12 @@ namespace CodeWalker Jetpack = 10, } - + public enum WorldSnapMode + { + None = 0, + Grid = 1, + Ground = 2, + Hybrid = 3, + } } diff --git a/WorldForm.resx b/WorldForm.resx index 1687a09..091ca9d 100644 --- a/WorldForm.resx +++ b/WorldForm.resx @@ -398,6 +398,43 @@ ufo rp3fhGJScIRLzKMLFTC9cMIu3nCDVUyjB6WkYA93mEWbAyH9cMImPuA+rWMA31YwBU82kF6BS32Er/aO M8zAh+OEghpcwQ2bg3uwBW8ewFd7xQkm0IA4oaAS7bh2KHjBIZbhV/D6GJkFphrdcIP8lFrAGPwPOjCO QdQiTqrAWNICd7gPnUj+xBKaU9dxfhTkjwV/FxU+AbsiGnc46OYIAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACtSURBVDhPrZBBEsIgEAR5Gy/wFV55T/wHr+KgHuCKNsVY + ZI2JiU7VVIVlp7OL+1mllIr7cb8Ie++PQwQYITnnM24NWxoBgsQYm/l+gk699bMsRA4h1JTSPsg0Xert + em/mGwh3vW1Z7MvIABSWqXG3+iZHAEw1m4wD49oVANgVOL/VeSgeDAiX1mpWeKy9BIQiI+OxWQF77tG5 + 2Fc729BmeElf/3lNhORe+oecewDObEqX49RqCgAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAAzElEQVQ4T62SwQ3DIAxFMxsT + dIpcmSfdg6lyaHuAq8t3/BFxEVKbWnoVcfxfIM0iIpdYSiliDAfAtBAOIUwl06Kgl1RW4zsBJSklBeuc + 881Gx4WneAmJMcq+7yrxxyIUNMm23eX5eClYQ4J7Pkj0pw6s2DIEDBP07DjtnfxFUNe6M15oA9v1R4DA + hnWOYfabAC8KLwwS3PRgGHMMs2f/xVGQoIkt27Y/JP7aokd159MPqQ6dntiDfsWSVp3AMwyDU00EgMEW + Bi30G7K8AZnoeUPBv6fIAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAB+SURBVDhPvZBBCsAgDAR9my/oT3yP/aKHtge9WlaSkuYg + QdIuDMgmWY3BXa21LiHbLgzFGAf/B9RaNx0Aj8pzobGU0lNKTwDO8KYhuIXBQM57P49rgDM82aN57Qx4 + mJE1jV8As7QCa/kTpdCIVPlE8zBLB5Btl0uAhOyvFMINKNheKPQq5RMAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAAy0lEQVQ4T6WR0Q3CMAxEM1sW + 6hhI2aDs0an6AXy0vyZ39SFjCgJq6UmJe3dx0mJmhyjruprDRtgTij4VRLXWR4j26n0dEEKstUZ+DlDI + NE0E62VZTi7dry56CRHDMNg8zwzBJHvQLGAax7NdLzeCNUKiJsMA3BcjI0BmgR6+QaPJxKGApwkExs1X + iOKI+nyIvih4KDwYQuJJwo08MPb8X2yFEDQxMohiGfLerVv5NLwvwDqbornjTi8FZFHspb47vRSQoPBN + bzP9j5U7+VKHq71UybkAAAAASUVORK5CYII=