Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVG serialization big changes #983

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
116 changes: 116 additions & 0 deletions Elements.Serialization.SVG/src/BaseDrawing.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using System.Collections.Generic;
using System.Linq;
using Elements.Geometry;

namespace Elements.Serialization.SVG
{
/// <summary>
/// Base class for SVG documents
/// </summary>
public abstract class SvgBaseDrawing
{
/// <summary>
/// Scale applied to the model.
/// Usually it's a PageHeight to a ViewBoxHeight ratio (or a PageWidth to a ViewBoxWidth)
/// </summary>
public double Scale { get; protected set; }
/// <summary>
/// The width of the model bounding box.
/// </summary>
public float ViewBoxWidth
{
get { return _viewBoxWidth; }
protected set { _viewBoxWidth = value; }
}
/// <summary>
/// The height of the model bounding box.
/// </summary>
public float ViewBoxHeight
{
get { return _viewBoxHeight; }
protected set { _viewBoxHeight = value; }
}

/// <summary>
/// Get the scene bounds.
/// </summary>
public BBox3 SceneBounds
{
get { return _sceneBounds; }
protected set { _sceneBounds = value; }
}

/// <summary>
/// Computes scene bounds
/// </summary>
/// <param name="models">The set of the models</param>
/// <returns>Returns the boundinf box around the input models</returns>
public static BBox3 ComputeSceneBounds(IList<Model> models)
{
var bounds = new BBox3(Vector3.Max, Vector3.Min);
foreach (var model in models)
{
foreach (var element in model.Elements)
{
if (element.Value is GeometricElement geo)
{
geo.UpdateRepresentations();
if ((geo.Representation == null || geo.Representation.SolidOperations.All(v => v.IsVoid)) &&
(geo.RepresentationInstances == null || !geo.RepresentationInstances.Any()))
{
continue;
}
geo.UpdateBoundsAndComputeSolid();

if (geo.Bounds.Volume.ApproximatelyEquals(0))
{
continue;
}

var bbMax = geo.Transform.OfPoint(geo.Bounds.Max);
var bbMin = geo.Transform.OfPoint(geo.Bounds.Min);
bounds.Extend(new[] { bbMax, bbMin });
}
}
}

return bounds;
}

/// <summary>
/// Gets the rotation angle that must be applied to the plan.
/// </summary>
/// <param name="models">The set of the models.</param>
/// <param name="rotation">The orientation for a plan relative to the page.</param>
/// <param name="angle">The angle value that must be applied if rotation is Angle</param>
/// <returns>The angle in degrees</returns>
protected static double GetRotationValueForPlan(IList<Model> models, PlanRotation rotation, double angle)
{
if (rotation == PlanRotation.Angle)
{
return angle;
}

var grids = models.SelectMany(m => m.AllElementsOfType<GridLine>()).Select(gl => gl.Curve).Where(gl => gl is Line).ToList();
if (!grids.Any())
{
return 0.0;
}

var longest = (Line)grids.OrderBy(g => g.Length()).First();

return rotation switch
{
PlanRotation.LongestGridHorizontal => -longest.Direction().PlaneAngleTo(Vector3.YAxis),
PlanRotation.LongestGridVertical => -longest.Direction().PlaneAngleTo(Vector3.XAxis),
PlanRotation.Angle => angle,
PlanRotation.None => 0.0,
_ => 0.0,
};
}

private BBox3 _sceneBounds;
private float _viewBoxHeight;
private float _viewBoxWidth;
}
}
36 changes: 36 additions & 0 deletions Elements.Serialization.SVG/src/DrawingActions/DrawPolygon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Elements.Geometry;

namespace Elements.Serialization.SVG
{
/// <summary>
/// Draw polygon action
/// </summary>
public class DrawPolygon : DrawingAction
{
/// <summary>
/// Initializes a new instance for DrawPolygon class.
/// </summary>
/// <param name="polygon">The polygon.</param>
/// <param name="context">The svg context that can be used to draw the polygon (color, line thickness, etc.)</param>
/// <param name="text">The text inside the polygon.</param>
public DrawPolygon(Polygon polygon, SvgContext context, string text = "")
{
_polygon = polygon;
_text = text;
_context = context;
}

/// <summary>
/// Draws the polygon.
/// </summary>
/// <param name="canvas">The canvas where the polygon will be added.</param>
public override void Draw(BaseSvgCanvas canvas)
{
canvas.DrawPolygon(_polygon, _context);
}

private Polygon _polygon;
private string _text;
private SvgContext _context;
}
}
36 changes: 36 additions & 0 deletions Elements.Serialization.SVG/src/DrawingActions/DrawText.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Elements.Geometry;

namespace Elements.Serialization.SVG
{
/// <summary>
/// Draw text action
/// </summary>
public class DrawText : DrawingAction
{
/// <summary>
/// Initializes a new instance for DrawText class.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="transform">The transformation of the text.</param>
/// <param name="context">The svg context that can be used to draw the text (color, line thickness, etc.)</param>
public DrawText(string text, Transform transform, SvgContext context)
{
_text = text;
_transform = transform;
_context = context;
}

/// <summary>
/// Draws the text.
/// </summary>
/// <param name="canvas">The canvas where the text will be added.</param>
public override void Draw(BaseSvgCanvas canvas)
{
canvas.DrawText(_text, _transform, _context);
}

private string _text;
private Transform _transform;
private SvgContext _context;
}
}
14 changes: 14 additions & 0 deletions Elements.Serialization.SVG/src/DrawingActions/DrawingAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Elements.Serialization.SVG
{
/// <summary>
/// The drawing action (e.g. draw polygon, text)
/// </summary>
public abstract class DrawingAction
{
/// <summary>
/// Draw something using input drawing tool
/// </summary>
/// <param name="canvas">The canvas where the element will be added</param>
public abstract void Draw(BaseSvgCanvas canvas);
}
}
91 changes: 91 additions & 0 deletions Elements.Serialization.SVG/src/DrawingTools/BaseCanvas.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System.Linq;
using Elements.Geometry;

namespace Elements.Serialization.SVG
{
/// <summary>
/// The SVG drawing tool
/// </summary>
public abstract class BaseSvgCanvas
{
/// <summary>
/// The bounds of the scene.
/// </summary>
protected BBox3 SceneBounds { get; set; }
/// <summary>
/// The SVG document
/// </summary>
protected SvgBaseDrawing Document { get; }

/// <summary>
/// The height of the page.
/// </summary>
public double PageHeight { get; set; }
/// <summary>
/// The width of the page.
/// </summary>
public double PageWidth { get; set; }

/// <summary>
/// Initializes a new instance of BaseDrawingTool.
/// </summary>
/// <param name="document">The SVG document.</param>
public BaseSvgCanvas(SvgBaseDrawing document)
{
Document = document;
}

/// <summary>
/// Sets the scene bounds
/// </summary>
/// <param name="sceneBounds">The scene bounding box.</param>
/// <param name="rotation">The plan rotation angle (in degrees).</param>
public virtual void SetBounds(BBox3 sceneBounds, double rotation)
{
SceneBounds = sceneBounds;
var transform = new Transform(Vector3.Origin);
transform.Rotate(rotation);
var bounds = new BBox3(sceneBounds.Corners().Select(v => transform.OfPoint(v)));
var viewBoxWidth = (float)(bounds.Max.X - bounds.Min.X);
var viewBoxHeight = (float)(bounds.Max.Y - bounds.Min.Y);

PageHeight = viewBoxHeight;
PageWidth = viewBoxWidth;
}

/// <summary>
/// Draw polygon logic.
/// </summary>
/// <param name="polygon">The polygon.</param>
/// <param name="context">The svg context that can be used to draw the polygon (color, line thickness, etc.)</param>
public abstract void DrawPolygon(Polygon polygon, SvgContext context);

/// <summary>
/// Draw text logic.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="transform">The text transformation matrix.</param>
/// <param name="context">The svg context that can be used to draw the text (color, line thickness, etc.)</param>
public abstract void DrawText(string text, Transform transform, SvgContext context);

/// <summary>
/// Draw line logic.
/// </summary>
/// <param name="line">The line.</param>
/// <param name="context"></param>
public abstract void DrawLine(Line line, SvgContext context);

/// <summary>
/// Draw circle logic.
/// </summary>
/// <param name="center">The circle center.</param>
/// <param name="radius">The circle radius.</param>
/// <param name="context">The svg context that can be used to draw the circle (color, line thickness, etc.)</param>
public abstract void DrawCircle(Vector3 center, double radius, SvgContext context);

/// <summary>
/// Close the document.
/// </summary>
public abstract void Close();
}
}