Files
RevitSdkSamples/SDK/Samples/WinderStairs/CS/Winders/WinderSinglePoint.cs
T
2019-09-11 14:43:53 +02:00

239 lines
9.8 KiB
C#

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
namespace Revit.SDK.Samples.WinderStairs.CS
{
/// <summary>
/// This represents a single point winder corner.
/// </summary>
class WinderSinglePoint : WinderCorner
{
/*
* Direction1
* |
* |
* V *(CenterPoint)
* |
* |
* |----->---- Direction2
* CornerPoint
*/
/// <summary>
/// Calculated point: All the riser lines are pass through this point.
/// </summary>
public XYZ CenterPoint { get; private set; }
/// <summary>
/// Constructor to initialize the basic fields of the winder region.
/// </summary>
/// <param name="cornerPnt">Corner Point</param>
/// <param name="dir1">Enter direction</param>
/// <param name="dir2">Leave direction</param>
/// <param name="steps">Number of steps</param>
public WinderSinglePoint(XYZ cornerPnt, XYZ dir1, XYZ dir2, uint steps)
: base(cornerPnt, dir1, dir2, steps)
{
}
/// <summary>
/// Calculate the CenterPoint base on Australia single-point layout algorithm.
/// </summary>
/// <param name="runWidth">Stairs Runwidth</param>
/// <param name="offset1">CenterPoint Offset from the first inner boundary</param>
/// <param name="offset2">CenterPoint Offset from the second inner boundary</param>
public void Construct(double runWidth, double offset1, double offset2)
{
XYZ bisectDir = (Direction2 - Direction1).Normalize();
XYZ perpendicularDir1 = new XYZ(-Direction1.Y, Direction1.X, 0);
XYZ perpendicularDir2 = new XYZ(-Direction2.Y, Direction2.X, 0);
if (bisectDir.DotProduct(perpendicularDir1) < 0)
{
perpendicularDir1 = perpendicularDir1.Negate();
perpendicularDir2 = perpendicularDir2.Negate();
}
Line line1Offset = Line.CreateUnbound(
CornerPoint + perpendicularDir1 * (runWidth + offset1), Direction1);
Line line2Offset = Line.CreateUnbound(
CornerPoint + perpendicularDir2 * (runWidth + offset2), Direction2);
IntersectionResultArray xsect;
line1Offset.Intersect(line2Offset, out xsect);
CenterPoint = xsect.get_Item(0).XYZPoint;
Line line1 = Line.CreateUnbound(CornerPoint, Direction1.Negate());
Line line2 = Line.CreateUnbound(CornerPoint, Direction2);
var proj1 = line1.Project(CenterPoint);
var proj2 = line2.Project(CenterPoint);
Distance1 = proj1.Parameter;
Distance2 = proj2.Parameter;
}
/// <summary>
/// Generate the sketch base on the calculated CenterPoint:
/// Divide the corner into NumSteps evenly.
/// </summary>
public override void GenerateSketch(double runWidth,
IList<Curve> outerBoundary, IList<Curve> walkPath,
IList<Curve> innerBoundary, IList<Curve> riserLines)
{
// Calculate the bisect direction in the corner.
XYZ bisectDir = (Direction2 - Direction1).Normalize();
XYZ perpendicularDir1 = new XYZ(-Direction1.Y, Direction1.X, 0);
XYZ perpendicularDir2 = new XYZ(-Direction2.Y, Direction2.X, 0);
if (bisectDir.DotProduct(perpendicularDir1) < 0)
{
perpendicularDir1 = perpendicularDir1.Negate();
perpendicularDir2 = perpendicularDir2.Negate();
}
// Determine the rotation axis and the angle span in the corner.
double runwidth_2 = runWidth * 0.5;
XYZ zDir = XYZ.BasisZ;
double winderAngleSpan = perpendicularDir1.AngleOnPlaneTo(perpendicularDir2, zDir);
if (winderAngleSpan > Math.PI)
{
zDir = zDir.Negate();
winderAngleSpan = Math.PI * 2.0 - winderAngleSpan;
}
// Calculate the corner points
double diagonalDist = runwidth_2 / Math.Cos(winderAngleSpan * 0.5);
XYZ middleCornerPnt = CornerPoint + bisectDir * diagonalDist;
XYZ innerCornerPnt = middleCornerPnt + bisectDir * diagonalDist;
XYZ middleStart = StartPoint + perpendicularDir1 * runwidth_2;
XYZ innerStart = StartPoint + perpendicularDir1 * runWidth;
XYZ middleEnd = EndPoint + perpendicularDir2 * runwidth_2;
XYZ innerEnd = EndPoint + perpendicularDir2 * runWidth;
XYZ middleEnd0 = innerCornerPnt - perpendicularDir1 * runwidth_2;
XYZ middleEnd1 = innerCornerPnt - perpendicularDir2 * runwidth_2;
// Generate the two outer boundary lines
Line outerLine1 = Line.CreateBound(StartPoint, CornerPoint);
outerBoundary.Add(outerLine1);
Line outerLine2 = Line.CreateBound(CornerPoint, EndPoint);
outerBoundary.Add(outerLine2);
// Generate the first inner line
Line innerLine1 = null;
if (!innerStart.IsAlmostEqualTo(innerCornerPnt))
{
innerLine1 = Line.CreateBound(innerStart, innerCornerPnt);
innerBoundary.Add(innerLine1);
}
// Generate the second inner line
Line innerLine2 = null;
if (!innerCornerPnt.IsAlmostEqualTo(innerEnd))
{
innerLine2 = Line.CreateBound(innerCornerPnt, innerEnd);
innerBoundary.Add(innerLine2);
}
// Generate the first middle line
Line middleLine1 = null;
if (!middleStart.IsAlmostEqualTo(middleEnd0))
{
middleLine1 = Line.CreateBound(middleStart, middleEnd0);
walkPath.Add(middleLine1);
}
// Generate the middle fillet arc
XYZ middleCenter = innerCornerPnt - bisectDir * runwidth_2;
Arc middleArc = Arc.Create(middleEnd0, middleEnd1, middleCenter);
walkPath.Add(middleArc);
// Genera the second middle line
Line middleLine2 = null;
if (!middleEnd1.IsAlmostEqualTo(middleEnd))
{
middleLine2 = Line.CreateBound(middleEnd1, middleEnd);
walkPath.Add(middleLine2);
}
//
// Generate the riser lines by dividing the corner into NumSteps evenly.
//
double winderAnglePerStep = winderAngleSpan / NumSteps;
Transform tsf = Transform.CreateRotation(zDir, winderAnglePerStep);
XYZ currentDir = perpendicularDir1;
for (int i = 0; i < NumSteps - 1; ++i)
{
XYZ rayDir = tsf.OfVector(currentDir); currentDir = rayDir;
Line ray = Line.CreateUnbound(CenterPoint, rayDir);
IntersectionResultArray xsect;
if (ray.Intersect(outerLine1, out xsect) == SetComparisonResult.Overlap ||
ray.Intersect(outerLine2, out xsect) == SetComparisonResult.Overlap)
{
XYZ xOuter = xsect.get_Item(0).XYZPoint;
XYZ xInner = null;
if (innerLine1 == null || innerLine2 == null)
{
if (ray.Distance(innerCornerPnt) < 1.0e-9)
{
xInner = innerCornerPnt;
}
}
if (xInner == null)
{
if (innerLine1 != null && ray.Intersect(innerLine1, out xsect) == SetComparisonResult.Overlap)
{
xInner = xsect.get_Item(0).XYZPoint;
}
else if (innerLine2 != null && ray.Intersect(innerLine2, out xsect) == SetComparisonResult.Overlap)
{
xInner = xsect.get_Item(0).XYZPoint;
}
}
if (xInner == null)
{
throw new ArgumentException("Bad Input.");
}
riserLines.Add(Line.CreateBound(xOuter, xInner));
}
else
{
throw new ArgumentException("Bad Input.");
}
}
}
/// <summary>
/// Move the center point
/// </summary>
public override void Move(XYZ vector)
{
base.Move(vector);
CenterPoint += vector;
}
}
}