namespace conceptual
{
// abstract wall base type for common operations
public abstract class WallSegment
{
protected WallSegment( WallNode startNode, WallNode endNode )
{
this.StartNode = startNode;
this.EndNode = endNode;
}
public WallNode StartNode {get;set;}
public WallNode EndNode {get;set;}
public Point2d StartPoint
{
get
{
return this.StartNode.Position;
}
}
public Point2d EndPoint
{
get
{
return this.EndNode.Position;
}
}
public double Length
{
get
{
Curve2d curve = this.Curve;
return curve.GetLength(
curve.GetParameterOf( curve.StartPoint ),
curve.GetParameterOf( curve.EndPoint )
);
}
}
public abstract Curve2d Curve {get;}
}
// Concrete linear wall segment:
public class LinearWallSegment : WallSegment
{
public LinearWallSegment( WallNode startNode, WallNode endNode )
: base( startNode, endNode )
{
}
public override Curve2d Curve
{
get
{
return new LineSegment2d
( this.StartNode.Position,
this.EndNode.Position ); }
}
}
// concrete arc wall segment:
public class ArcWallSegment : WallSegment
{
public ArcWallSegment( WallNode startNode, WallNode endNode, double bulge, bool bulgeFlag )
: base( startNode, endNode )
{
this.Bulge = bulge;
this.BulgeFlag = bulgeFlag;
}
public bool BulgeFlag {get;set;}
public double Bulge {get;set;}
public override Curve2d Curve
{
get
{
return new CircularArc2d
( this.StartPoint,
this.EndPoint,
this.Bulge,
this.BulgeFlag ); }
}
}
// represents the position of the start or end of a wall:
public class WallNode
{
public WallNode( int nodeId, Point2d position )
{
this.nodeId = nodeId;
this.Position = position;
}
int nodeId;
public int Id {get { return this.nodeId;}}
public Point2d Position {get;set;}
}
// Encapsulation of a model of connected walls:
public class FloorPlanModel
{
int nextNode = 0;
List
<WallSegment
> walls
= new List
<WallSegment
>(); List
<WallNode
> nodes
= new List
<WallNode
>();
public List<WallSegment> Walls {get {return walls;}}
public List<WallNode> Nodes {get {return nodes;}}
// Add walls that span existing and/or new nodes:
public LinearWallSegment AddLinearWallSegment( Point2d startPoint, Point2d endPoint )
{
LinearWallSegment wall
= new LinearWallSegment
( GetNode( startPoint ),
GetNode( endPoint )
);
walls.Add( wall );
return wall;
}
public ArcWallSegment AddArcWallSegment( Point2d startPoint, Point2d endPoint, double bulge, bool flag )
{
ArcWallSegment wall
= new ArcWallSegment
( GetNode( startPoint ),
GetNode( endPoint ),
bulge,
flag
);
walls.Add( wall );
return wall;
}
public WallNode GetNode( Point2d point, bool add = true )
{
WallNode node = nodes.FirstOrDefault( n => n.Position.GetDistanceTo( point ) < 0.1 );
if( node == null && add )
{
node
= new WallNode
( this.nextNode++, point
); nodes.Add( node );
}
return node;
}
// Example Analytical operations that leverage the use of a network
// to model floor plans
// This example returns all WallSegment objects
// connected to the node at the given point:
public IEnumerable<WallSegment> GetWallSegmentsAt( Point2d point )
{
WallNode node = GetNode( point, false );
if( node != null )
return walls.Where( wall => wall.StartNode == node || wall.EndNode == node );
else
return Enumerable.Empty<WallSegment>();
}
// Gets the WallSegments connected to the given wall segment:
public IEnumerable<WallSegment> GetConnectedWalls( WallSegment ws )
{
WallNode a = ws.StartNode;
WallNode b = ws.EndNode;
return walls.Where( w => w != ws &&
w.StartNode == a || w.EndNode == a ||
w.StartNode == b || w.EndNode == b
);
}
// Get the wall segment the given point is on,
// or is near to within the specified fuzz:
public WallSegment GetWallSegmentAt( Point2d point, double fuzz )
{
Tolerance t
= new Tolerance
( Tolerance
.Global.EqualVector, fuzz
); return walls.FirstOrDefault( w => w.Curve.IsOn( point, t ) );
}
// Get the wall segment whose defining curve is closest to the given point:
public WallSegment GetWallSegmentNearestTo( Point2d point )
{
return walls
.Select( w
=> new {Wall
= w, Distance
= w
.Curve.GetDistanceTo( point
)} ) .Aggregate( ( a, b ) => a.Distance < b.Distance ? a : b )
.Wall;
}
// Get the sum of the length of all wall segments:
public double TotalLength
{
get
{
return walls.Sum( w => w.Length );
}
}
}