应用程序: SlabShapeEditing

Revit平台: Architecture, Structure

Revit版本: 2011.0

首次发布: 2009.0

编程语言: C#

技能水平: 中等

类别: 几何, 元素

类型: ExternalCommand

主题: 创建SlabShapeVertexSlabShapeCrease

摘要:

本示例演示了如何创建SlabShapeVertexSlabShapeCrease,并使用它们来编辑板的形状。

相关类:

Autodesk.Revit.DB.SlabShapeEditor

Autodesk.Revit.DB.SlabShapeCrease

Autodesk.Revit.DB.SlabShapeCreaseArray

Autodesk.Revit.DB.SlabShapeCreaseArrayIterator

Autodesk.Revit.DB.SlabShapeVertex

Autodesk.Revit.DB.Line

Autodesk.Revit.DB.Edge

Autodesk.Revit.DB.CurveArray

Autodesk.Revit.DB.GeometryObject

项目文件:

Command.cs

此文件包含了实现IExternalCommand接口的Command类,获取选择的板,创建SlabShapeEditingForm和获取ExternalCommandData

 

SlabShapeEditingForm.cs

此文件包含一个继承自FormSlabShapeEditingForm类。此窗体包含一个PictureBox,用于显示板的几何信息,以及一些用于创建顶点和折痕的按钮。

 

SlabProfile.cs

此文件包含一个用于计算板几何信息的SlabProfile类。SlabProfileDraw2D()AddVertex()AddCrease()方法组成。Draw2D()用于在图片框上绘制板曲线,而AddVertex()AddCrease()用于在板上创建顶点和折痕。

 

LineTool.cs

此文件包含一个LineTool类,它提供了一些方法用于在窗体上绘制线条并存储所绘制线条的数据。它还提供了将新创建的顶点作为矩形绘制的方法。

 

MathTools.cs

此文件包含两个类:Verctor4Matrix4。这两个类用于在3D2D之间转换点。

描述:

本示例演示了如何:

1. 通过SlabShapeEditor.DrawPoint(Autodesk.Revit.Geometry.XYZ location)方法创建SlabShapeVertex

2. 通过SlabShapeEditor.DrawSplitLine(SlabShapeVertex startVertex, SlabShapeVertex endVertex)方法创建SlabShapeCrease。一个折痕由两个顶点组成。

3. 通过SlabShapeEditor.ModifySubElement(SlabShapeVertex pVertex, double offset)方法移动新创建的顶点。

4. 通过SlabShapeEditor.ModifySubElement(SlabShapeCrease pCrease, double offset)方法移动新创建的折痕,偏移量用于设置折线中点的位置。

说明:

1.Revit中绘制一个板或打开CreateComplexAreaRein.rvt文件,然后选择该板。

2.运行此命令。

3.点击“创建顶点”按钮,在图片框中单击鼠标创建板上的顶点。

4.点击“创建折痕”按钮,在图片框中单击鼠标创建板上的折痕。

5.点击“选择”按钮,然后移动鼠标,在图片框中单击以选择新创建的顶点或折痕。当新顶点或折痕变为红色时,表示您已经成功选择了它。

6.然后在文本框中输入用户想要移动的距离(只需输入数字,单位是英尺),然后单击“更新”按钮。

7.点击“重置”按钮以恢复板的原始形状。

8.如果用户想以不同的方向观察板,只需在图片框中按下鼠标右键并移动鼠标即可。

源代码:
完整的源代码请加入QQ群649037449,在群文件中下载RevitSDK.exe,解压后在文件夹中搜索本文中应用程序名称即可获得完整源码

LineTool.cs

//
// (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 System.Text;
using System.Drawing;
using System.Collections;
namespace Revit.SDK.Samples.SlabShapeEditing.CS
{
    /// <summary>
    /// tool used to draw line
    /// </summary>
    class LineTool
    {
        #region class member variables
        ArrayList m_Points; //record all the points draw by this tool
        PointF m_movePoint; //record the coordinate of location where mouse just moved to. 
        #endregion 
        /// <summary>
        /// Get all the points of this tool
        /// </summary>
        public ArrayList Points
        {
            get
            {
                return m_Points;
            }
            set
            {
                m_Points = value;
            }
        }
        /// <summary>
        ///Get coordinate of location where mouse just moved to.
        /// </summary>
        public PointF MovePoint
        {
            get
            {
                return m_movePoint;
            }
            set
            {
                m_movePoint = value;
            }
        }
        /// <summary>
        /// default constructor
        /// </summary>
        public LineTool() 
        {
            m_Points = new ArrayList();
            m_movePoint = Point.Empty;
        }
        /// <summary>
        /// draw the stored lines
        /// </summary>
        /// <param name="graphics">Graphics object, used to draw geometry</param>
        /// <param name="pen">Pen which used to draw lines</param>
        public void Draw2D(Graphics graphics, Pen pen)
        {
            for (int i = 0; i < m_Points.Count - 1; i+=2)
            {
                graphics.DrawLine(pen, (PointF)m_Points[i], (PointF)m_Points[i+1]);
            }
            //draw the moving point
            if (!m_movePoint.IsEmpty)
            {
                if (m_Points.Count >= 1)
                {
                    graphics.DrawLine(pen, (PointF)m_Points[m_Points.Count - 1], m_movePoint);
                }
            }
        }
        /// <summary>
        /// draw rectangle with specific graphics and pen
        /// </summary>
        /// <param name="graphics">Graphics object, used to draw geometry</param>
        /// <param name="pen">Pen which used to draw lines</param>
        public void DrawRectangle(Graphics graphics, Pen pen)
        {
            for (int i = 0; i < m_Points.Count - 1; i += 2)
            {
                PointF pointF = (PointF)m_Points[i];
                graphics.DrawRectangle(pen, pointF.X-2, pointF.Y-2, 4, 4);
            }
        }
    }
}

MathTools.cs

//
// (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 System.Text;
using Autodesk.Revit.DB;

namespace Revit.SDK.Samples.SlabShapeEditing.CS
{
/// <summary>
/// Vector4 is a homogeneous coordinate class used to store vector
/// and contain method to handle the vector
/// </summary>
public class Vector4
{
#region Class member variables and properties
private double m_x;
private double m_y;
private double m_z;
private double m_w = 1.0f;

/// <summary>
/// X property to get/set x value of Vector4
/// </summary>
public double X
{
get
{
return m_x;
}
set
{
m_x = value;
}
}

/// <summary>
/// Y property to get/set y value of Vector4
/// </summary>
public double Y
{
get
{
return m_y;
}
set
{
m_y = value;
}
}

/// <summary>
/// Z property to get/set z value of Vector4
/// </summary>
public double Z
{
get
{
return m_z;
}
set
{
m_z = value;
}
}

/// <summary>
/// W property to get/set fourth value of Vector4
/// </summary>
public double W
{
get
{
return m_w;
}
set
{
m_w = value;
}
}
#endregion

/// <summary>
/// constructor
/// </summary>
public Vector4(double x, double y, double z)
{
this.X = x; this.Y = y; this.Z = z;
}

/// <summary>
/// constructor, transfer Autodesk.Revit.DB.XYZ to vector
/// </summary>
/// <param name="v">Autodesk.Revit.DB.XYZ structure which needs to be transferred</param>
public Vector4(Autodesk.Revit.DB.XYZ v)
{
this.X = (double)v.X; this.Y = (double)v.Y; this.Z = (double)v.Z;
}

/// <summary>
/// adds two vectors
/// </summary>
/// <param name="va">first vector</param>
/// <param name="vb">second vector</param>
public static Vector4 operator+ (Vector4 va, Vector4 vb)
{
return new Vector4(va.X + vb.X, va.Y + vb.Y, va.Z + vb.Z);
}

/// <summary>
/// subtracts two vectors
/// </summary>
/// <param name="va">first vector</param>
/// <param name="vb">second vector</param>
/// <returns>subtraction of two vectors</returns>
public static Vector4 operator- (Vector4 va, Vector4 vb)
{
return new Vector4(va.X - vb.X, va.Y - vb.Y, va.Z - vb.Z);
}

/// <summary>
/// multiplies a vector by a double type value
/// </summary>
/// <param name="v">vector</param>
/// <param name="factor">multiplier of double type</param>
/// <returns> the result vector </returns>
public static Vector4 operator *(Vector4 v, double factor)
{
return new Vector4(v.X * factor, v.Y * factor, v.Z * factor);
}

/// <summary>
/// divides vector by a double type value
/// </summary>
/// <param name="v">vector</param>
/// <param name="factor">double type value</param>
/// <returns> vector divided by a double type value </returns>
public static Vector4 operator /(Vector4 v, double factor)
{
return new Vector4(v.X / factor, v.Y / factor, v.Z / factor);
}

/// <summary>
/// dot multiply vector
/// </summary>
/// <param name="v"> the result vector </param>
public double DotProduct(Vector4 v)
{
return (this.X * v.X + this.Y * v.Y + this.Z * v.Z);
}

/// <summary>
/// get normal vector of plane contains two vectors
/// </summary>
/// <param name="v">second vector</param>
/// <returns> normal vector of two vectors</returns>
public Vector4 CrossProduct(Vector4 v)
{
return new Vector4(this.Y * v.Z - this.Z * v.Y,this.Z * v.X
- this.X * v.Z,this.X * v.Y - this.Y * v.X);
}

/// <summary>
/// dot multiply two vectors
/// </summary>
/// <param name="va">first vector</param>
/// <param name="vb">second vector</param>
public static double DotProduct(Vector4 va, Vector4 vb)
{
return (va.X * vb.X + va.Y * vb.Y + va.Z * vb.Z);
}

/// <summary>
/// get normal vector of two vectors
/// </summary>
/// <param name="va">first vector</param>
/// <param name="vb">second vector</param>
/// <returns> normal vector of two vectors </returns>
public static Vector4 CrossProduct(Vector4 va, Vector4 vb)
{
return new Vector4(va.Y * vb.Z - va.Z * vb.Y, va.Z * vb.X
- va.X * vb.Z, va.X * vb.Y - va.Y * vb.X);
}

/// <summary>
/// get unit vector
/// </summary>
public void Normalize()
{
double length = Length();
if(length == 0)
{
length = 1;
}
this.X /= length;
this.Y /= length;
this.Z /= length;
}

/// <summary>
/// calculate the length of vector
/// </summary>
public double Length()
{
return (double)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z);
}
};

/// <summary>
/// Matrix used to transform between ucs coordinate and world coordinate.
/// </summary>
public class Matrix4
{
#region MatrixType
/// <summary>
/// Matrix Type Enum use to define function of matrix
/// </summary>
public enum MatrixType
{
Rotation, // matrix use to rotate
Translation, // matrix used to Translation
Scale, // matrix used to Scale
RotationAndTranslation, // matrix used to Rotation and Translation
Normal // normal matrix
};
private double[,] m_matrix = new double[4,4]; // an array stores the matrix
private MatrixType m_type; //type of matrix
#endregion

/// <summary>
/// X property to get/set Type of matrix
/// </summary>
public MatrixType Type
{
get
{
return m_type;
}
set
{
m_type = value;
}
}

/// <summary>
/// X property to get/set Array which store data for matrix
/// </summary>
public double[,] Matrix
{
get
{
return m_matrix;
}
set
{
m_matrix = value;
}
}

/// <summary>
/// get a matrix used to rotate object specific angle on X direction
/// </summary>
/// <param name="angle">rotate angle</param>
/// <returns>matrix which rotate object specific angle on X direction</returns>
public static Matrix4 RotateX(double angle)
{
Matrix4 rotateX = new Matrix4();
rotateX.Type = MatrixType.Rotation;
rotateX.Identity();
double sin = (double)Math.Sin(angle);
double cos = (double)Math.Cos(angle);
rotateX.Matrix[1, 1] = cos;
rotateX.Matrix[1, 2] = sin;

rotateX.Matrix[2, 1] = -sin;
rotateX.Matrix[2, 2] = cos;
return rotateX;
}

/// <summary>
/// get a matrix used to rotate object specific angle on Y direction
/// </summary>
/// <param name="angle">rotate angle</param>
/// <returns>matrix which rotate object specific angle on Y direction</returns>
public static Matrix4 RotateY(double angle)
{
Matrix4 rotateX = new Matrix4();
rotateX.Type = MatrixType.Rotation;
rotateX.Identity();
double sin = (double)Math.Sin(angle);
double cos = (double)Math.Cos(angle);
rotateX.Matrix[0, 0] = cos;
rotateX.Matrix[0, 2] = -sin;

rotateX.Matrix[2, 0] = sin;
rotateX.Matrix[2, 2] = cos;
return rotateX;
}

/// <summary>
/// get a matrix used to rotate object specific angle on Z direction
/// </summary>
/// <param name="angle">rotate angle</param>
/// <returns>matrix which rotate object specific angle on Z direction</returns>
public static Matrix4 RotateZ(double angle)
{
Matrix4 rotateX = new Matrix4();
rotateX.Type = MatrixType.Rotation;
rotateX.Identity();
double sin = (double)Math.Sin(angle);
double cos = (double)Math.Cos(angle);
rotateX.Matrix[1, 1] = cos;
rotateX.Matrix[1, 2] = sin;

rotateX.Matrix[2, 1] = -sin;
rotateX.Matrix[2, 2] = cos;
return rotateX;
}

/// <summary>
/// default constructor
/// </summary>
public Matrix4()
{
m_type = MatrixType.Normal;
Identity();
}

/// <summary>
/// ctor,rotation matrix,origin at (0,0,0)
/// </summary>
/// <param name="xAxis">identity of x axis</param>
/// <param name="yAxis">identity of y axis</param>
/// <param name="zAxis">identity of z axis</param>
public Matrix4(Vector4 xAxis,Vector4 yAxis, Vector4 zAxis)
{
m_type = MatrixType.Rotation;
Identity();
m_matrix[0, 0] = xAxis.X; m_matrix[0, 1] = xAxis.Y; m_matrix[0, 2] = xAxis.Z;
m_matrix[1, 0] = yAxis.X; m_matrix[1, 1] = yAxis.Y; m_matrix[1, 2] = yAxis.Z;
m_matrix[2, 0] = zAxis.X; m_matrix[2, 1] = zAxis.Y; m_matrix[2, 2] = zAxis.Z;
}

/// <summary>
/// ctor,translation matrix.
/// </summary>
/// <param name="origin">origin of ucs in world coordinate</param>
public Matrix4(Vector4 origin)
{
m_type = MatrixType.Translation;
Identity();
m_matrix[3, 0] = origin.X; m_matrix[3, 1] = origin.Y; m_matrix[3, 2] = origin.Z;
}

/// <summary>
/// rotation and translation matrix constructor
/// </summary>
/// <param name="xAxis">x Axis</param>
/// <param name="yAxis">y Axis</param>
/// <param name="zAxis">z Axis</param>
/// <param name="origin">origin</param>
public Matrix4(Vector4 xAxis, Vector4 yAxis, Vector4 zAxis, Vector4 origin)
{
m_type = MatrixType.RotationAndTranslation;
Identity();
m_matrix[0, 0] = xAxis.X; m_matrix[0, 1] = xAxis.Y; m_matrix[0, 2] = xAxis.Z;
m_matrix[1, 0] = yAxis.X; m_matrix[1, 1] = yAxis.Y; m_matrix[1, 2] = yAxis.Z;
m_matrix[2, 0] = zAxis.X; m_matrix[2, 1] = zAxis.Y; m_matrix[2, 2] = zAxis.Z;
m_matrix[3, 0] = origin.X; m_matrix[3, 1] = origin.Y; m_matrix[3, 2] = origin.Z;
}

/// <summary>
/// scale matrix constructor
/// </summary>
/// <param name="scale">scale factor</param>
public Matrix4(double scale)
{
m_type = MatrixType.Scale;
Identity();
m_matrix[0, 0] = scale;
m_matrix[1, 1] = scale;
m_matrix[2, 2] = scale;
}

/// <summary>
/// indexer of matrix
/// </summary>
/// <param name="row">row number</param>
/// <param name="column">column number</param>
/// <returns></returns>
public double this[int row, int column]
{
get
{
return this.m_matrix[row, column];
}
set
{
this.m_matrix[row, column] = value;
}
}

/// <summary>
/// Identity matrix
/// </summary>
public void Identity()
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
this.m_matrix[i, j] = 0.0f;
}
}
this.m_matrix[0, 0] = 1.0f;
this.m_matrix[1, 1] = 1.0f;
this.m_matrix[2, 2] = 1.0f;
this.m_matrix[3, 3] = 1.0f;
}

/// <summary>
/// multiply matrix left and right
/// </summary>
/// <param name="left">left matrix</param>
/// <param name="right">right matrix</param>
/// <returns></returns>
public static Matrix4 Multiply(Matrix4 left, Matrix4 right)
{
Matrix4 result = new Matrix4();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
result[i, j] = left[i, 0] * right[0, j] + left[i, 1] * right[1, j]
+ left[i, 2] * right[2, j] + left[i, 3] * right[3, j];
}
}
return result;
}

/// <summary>
/// transform point using this matrix
/// </summary>
/// <param name="point">point to be transformed</param>
/// <returns>transform result</returns>
public Vector4 Transform(Vector4 point)
{
return new Vector4(point.X * this[0, 0] + point.Y * this[1, 0]
+ point.Z * this[2, 0]+ point.W * this[3, 0],
point.X * this[0, 1] + point.Y * this[1, 1]
+ point.Z * this[2, 1]+ point.W * this[3, 1],
point.X * this[0, 2] + point.Y * this[1, 2]
+ point.Z * this[2, 2]+ point.W * this[3, 2]);
}

/// <summary>
/// if m_matrix is a rotation matrix,this method can get the rotation inverse matrix.
/// </summary>
/// <returns>inverse of rotation matrix</returns>
public Matrix4 RotationInverse()
{
return new Matrix4(new Vector4(this[0, 0], this[1, 0], this[2, 0]),
new Vector4(this[0, 1], this[1, 1], this[2, 1]),
new Vector4(this[0, 2], this[1, 2], this[2, 2]));
}

/// <summary>
/// if this m_matrix is a translation matrix,
/// this method can get the translation inverse matrix.
/// </summary>
/// <returns>inverse of translation matrix</returns>
public Matrix4 TranslationInverse()
{
return new Matrix4(new Vector4(-this[3, 0], -this[3, 1], -this[3, 2]));
}

/// <summary>
/// get inverse matrix
/// </summary>
/// <returns>inverse matrix</returns>
public Matrix4 Inverse()
{
switch(m_type)
{
case MatrixType.Rotation: return RotationInverse();

case MatrixType.Translation: return TranslationInverse();

case MatrixType.RotationAndTranslation:
return Multiply(TranslationInverse(),RotationInverse());

case MatrixType.Scale: return ScaleInverse();

case MatrixType.Normal: return new Matrix4();

default: return null;
}
}

/// <summary>
/// if m_matrix is a scale matrix,this method can get the scale inverse matrix.
/// </summary>
/// <returns>inverse of scale matrix</returns>
public Matrix4 ScaleInverse()
{
return new Matrix4(1 / m_matrix[0,0]);
}
};
}

SlabProfile.cs

//
// (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 System.Text;
using System.Collections;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Drawing;
using Autodesk.Revit;
using System.Windows.Forms;

namespace Revit.SDK.Samples.SlabShapeEditing.CS
{
/// <summary>
/// SlabProfile class contains Geometry information of Slab,
/// and contains methods used to edit slab's Shape.
/// </summary>
class SlabProfile
{
#region class member variables

ExternalCommandData m_commandData; //contains reference of Revit Application

Autodesk.Revit.DB.Floor m_floor; //object of truss in Revit

EdgeArray m_edges; // store all the edges of floor

PointF[] m_boundPoints; // store array store bound point of Slab

Matrix4 m_to2DMatrix = null; // store the Matrix used to transform 3D points to 2D

Matrix4 m_moveToCenterMatrix = null; // store the Matrix used to move points to center

Matrix4 m_scaleMatrix = null; // store the Matrix used to scale profile fit to pictureBox

Matrix4 m_MoveToPictureBoxCenter = null; // store the Matrix used to move profile to center of pictureBox

Matrix4 m_transformMatrix = null; // store the Matrix used to transform Revit coordinate to window UI

Matrix4 m_restoreMatrix = null; // store the Matrix used to transform window UI coordinate to Revit

Matrix4 m_rotateMatrix = null; //store the matrix which rotate object

const int m_sizeXPictureBox = 354; //save picture box's size.X

const int m_sizeYPictureBox = 280; //save picture box's size.Y

SlabShapeEditor m_slabShapeEditor; //SlabShapeEditor which use to editor shape of slab

double m_rotateAngleX = 0; //rotate angle in X direction

double m_rotateAngleY = 0; //rotate angle in Y direction

#endregion

/// <summary>
/// constructor
/// </summary>
/// <param name="floor">Floor object in Revit</param>
/// <param name="commandData">contains reference of Revit Application</param>
public SlabProfile(Autodesk.Revit.DB.Floor floor, ExternalCommandData commandData)
{
m_floor = floor;
m_commandData = commandData;
m_slabShapeEditor = floor.SlabShapeEditor;
GetSlabProfileInfo();
}

/// <summary>
/// Calculate geometry info for Slab
/// </summary>
public void GetSlabProfileInfo()
{
// get all the edges of the Slab
m_edges = GetFloorEdges();
// Get a matrix which can transform points to 2D
m_to2DMatrix = GetTo2DMatrix();
// get the boundary of all the points
m_boundPoints = GetBoundsPoints();
// get a matrix which can keep all the points in the center of the canvas
m_moveToCenterMatrix = GetMoveToCenterMatrix();
// get a matrix for scaling all the points and lines within the canvas
m_scaleMatrix = GetScaleMatrix();
// get a matrix for moving all point in the middle of PictureBox
m_MoveToPictureBoxCenter = GetMoveToCenterOfPictureBox();
// transform 3D points to 2D
m_transformMatrix = Get3DTo2DMatrix();
// transform from 2D to 3D
m_restoreMatrix = Get2DTo3DMatrix();
}

/// <summary>
/// Get all points of the Slab
/// </summary>
/// <returns>points array stores all the points on slab</returns>
public EdgeArray GetFloorEdges()
{
EdgeArray edges = new EdgeArray();
Options options = m_commandData.Application.Application.Create.NewGeometryOptions();
options.DetailLevel = ViewDetailLevel.Medium;
//make sure references to geometric objects are computed.
options.ComputeReferences = true;
Autodesk.Revit.DB.GeometryElement geoElem = m_floor.get_Geometry(options);
//GeometryObjectArray gObjects = geoElem.Objects;
IEnumerator<GeometryObject> Objects = geoElem.GetEnumerator();
//get all the edges in the Geometry object
//foreach (GeometryObject geo in gObjects)
while (Objects.MoveNext())
{
GeometryObject geo = Objects.Current;

Solid solid = geo as Solid;
if (solid != null)
{
FaceArray faces = solid.Faces;
foreach (Face face in faces)
{
EdgeArrayArray edgeArrarr = face.EdgeLoops;
foreach (EdgeArray edgeArr in edgeArrarr)
{
foreach (Edge edge in edgeArr)
{
edges.Append(edge);
}
}
}
}
}
return edges;
}

/// <summary>
/// Get a matrix which can transform points to 2D
/// </summary>
/// <returns>matrix which can transform points to 2D</returns>
public Matrix4 GetTo2DMatrix()
{
Vector4 xAxis = new Vector4(1, 0, 0);
//Because Y axis in windows UI is downward, so we should Multiply(-1) here
Vector4 yAxis = new Vector4(0, -1, 0);
Vector4 zAxis = new Vector4(0, 0, 1);

Matrix4 result = new Matrix4(xAxis, yAxis, zAxis);
return result;
}

/// <summary>
/// calculate the matrix use to scale
/// </summary>
/// <returns>maxtrix is use to scale the profile</returns>
public Matrix4 GetScaleMatrix()
{
float xScale = 384 / (m_boundPoints[1].X - m_boundPoints[0].X);
float yScale = 275 / (m_boundPoints[1].Y - m_boundPoints[0].Y);
float factor = xScale <= yScale ? xScale : yScale;
return new Matrix4((float)(factor * 0.85));
}

/// <summary>
/// Get a matrix which can move points to center of itself
/// </summary>
/// <returns>matrix used to move point to center of itself</returns>
public Matrix4 GetMoveToCenterMatrix()
{
//translate the origin to bound center
PointF[] bounds = GetBoundsPoints();
PointF min = bounds[0];
PointF max = bounds[1];
PointF center = new PointF((min.X + max.X) / 2, (min.Y + max.Y) / 2);
return new Matrix4(new Vector4(center.X, center.Y, 0));
}

/// <summary>
/// Get a matrix which can move points to center of picture box
/// </summary>
/// <returns>matrix used to move point to center of picture box</returns>
private Matrix4 GetMoveToCenterOfPictureBox()
{
return new Matrix4(new Vector4(m_sizeXPictureBox / 2, m_sizeYPictureBox / 2, 0));
}

/// <summary>
/// calculate the matrix used to transform 3D to 2D
/// </summary>
/// <returns>maxtrix is use to transform 3d points to 2d</returns>
public Matrix4 Get3DTo2DMatrix()
{
Matrix4 result = Matrix4.Multiply(
m_to2DMatrix.Inverse(), m_moveToCenterMatrix.Inverse());
result = Matrix4.Multiply(result, m_scaleMatrix);
return Matrix4.Multiply(result, m_MoveToPictureBoxCenter);
}

/// <summary>
/// calculate the matrix used to transform 2D to 3D
/// </summary>
/// <returns>maxtrix is use to transform 2d points to 3d</returns>
public Matrix4 Get2DTo3DMatrix()
{
Matrix4 matrix = Matrix4.Multiply(
m_MoveToPictureBoxCenter.Inverse(), m_scaleMatrix.Inverse());
matrix = Matrix4.Multiply(
matrix, m_moveToCenterMatrix);
return Matrix4.Multiply(matrix, m_to2DMatrix);
}

/// <summary>
/// Get max and min coordinates of all points
/// </summary>
/// <returns>points array stores the bound of all points</returns>
public PointF[] GetBoundsPoints()
{
Matrix4 matrix = m_to2DMatrix;
Matrix4 inverseMatrix = matrix.Inverse();
double minX = 0, maxX = 0, minY = 0, maxY = 0;
bool bFirstPoint = true;

//get all points on slab
List<XYZ> points = new List<XYZ>();
foreach (Edge edge in m_edges)
{
List<XYZ> edgexyzs = edge.Tessellate() as List<XYZ>;
foreach (Autodesk.Revit.DB.XYZ xyz in edgexyzs)
{ points.Add(xyz); }
}

//get the max and min point on the face
foreach (Autodesk.Revit.DB.XYZ point in points)
{
Vector4 v = new Vector4(point);
Vector4 v1 = inverseMatrix.Transform(v);

if (bFirstPoint)
{
minX = maxX = v1.X;
minY = maxY = v1.Y;
bFirstPoint = false;
}
else
{
if (v1.X < minX) { minX = v1.X; }
else if (v1.X > maxX) { maxX = v1.X; }

if (v1.Y < minY) { minY = v1.Y; }
else if (v1.Y > maxY) { maxY = v1.Y; }
}
}
//return an array with max and min value of all points
PointF[] resultPoints = new PointF[2] {
new PointF((float)minX, (float)minY), new PointF((float)maxX, (float)maxY) };
return resultPoints;
}

/// <summary>
/// draw profile of Slab in pictureBox
/// </summary>
/// <param name="graphics">form graphic</param>
/// <param name="pen">pen used to draw line in pictureBox</param>
public void Draw2D(Graphics graphics, Pen pen)
{
foreach (Edge edge in m_edges)
{
List<XYZ> edgexyzs = edge.Tessellate() as List<XYZ>;
DrawCurve(graphics, pen, edgexyzs);
}
}

/// <summary>
/// draw specific points in pictureBox
/// </summary>
/// <param name="graphics">form graphic</param>
/// <param name="pen">pen used to draw line in pictureBox</param>
/// <param name="points">points which need to be drawn</param>
public void DrawCurve(Graphics graphics, Pen pen, List<XYZ> points)
{
//draw slab curves
for (int i = 0; i < points.Count - 1; i += 1)
{
Autodesk.Revit.DB.XYZ point1 = points[i];
Autodesk.Revit.DB.XYZ point2 = points[i + 1];

Vector4 v1 = new Vector4(point1);
Vector4 v2 = new Vector4(point2);

v1 = m_transformMatrix.Transform(v1);
v2 = m_transformMatrix.Transform(v2);
if (m_rotateMatrix != null)
{
v1 = m_rotateMatrix.Transform(v1);
v2 = m_rotateMatrix.Transform(v2);
}
graphics.DrawLine(pen, new PointF((int)v1.X, (int)v1.Y),
new PointF((int)v2.X, (int)v2.Y));
}
}

/// <summary>
/// rotate slab with specific angle
/// </summary>
/// <param name="xAngle">rotate angle in X direction</param>
/// <param name="yAngle">rotate angle in Y direction</param>
public void RotateFloor(double xAngle, double yAngle)
{
if (0 == xAngle && 0 == yAngle) { return; }
m_rotateAngleX += xAngle;
m_rotateAngleY += yAngle;

Matrix4 rotateX = Matrix4.RotateX(m_rotateAngleX);
Matrix4 rotateY = Matrix4.RotateY(m_rotateAngleY);
Matrix4 rotateMatrix = Matrix4.Multiply(rotateX, rotateY);

m_rotateMatrix = Matrix4.Multiply(m_MoveToPictureBoxCenter.Inverse(), rotateMatrix);
m_rotateMatrix = Matrix4.Multiply(m_rotateMatrix, m_MoveToPictureBoxCenter);
}

/// <summary>
/// make rotate matrix null
/// </summary>
public void ClearRotateMatrix()
{
m_rotateMatrix = null;
}

/// <summary>
/// Reset index and clear line tool
/// </summary>
public void ResetSlabShape()
{
Transaction transaction = new Transaction(
m_commandData.Application.ActiveUIDocument.Document, "ResetSlabShape");
transaction.Start();
m_slabShapeEditor.ResetSlabShape();
transaction.Commit();
//re-calculate geometry info
GetSlabProfileInfo();
}

/// <summary>
/// Add vertex on specific location
/// </summary>
/// <param name="point">location where vertex add on</param>
/// <returns>new created vertex</returns>
public SlabShapeVertex AddVertex(PointF point)
{
Transaction transaction = new Transaction(
m_commandData.Application.ActiveUIDocument.Document, "AddVertex");
transaction.Start();
Vector4 v1 = new Vector4(new Autodesk.Revit.DB.XYZ(point.X, point.Y, 0));
v1 = m_restoreMatrix.Transform(v1);
SlabShapeVertex vertex = m_slabShapeEditor.DrawPoint(new Autodesk.Revit.DB.XYZ(v1.X, v1.Y, v1.Z));
transaction.Commit();
//re-calculate geometry info
GetSlabProfileInfo();

return vertex;
}

/// <summary>
/// Add Crease on specific location
/// </summary>
/// <param name="point1">first point of location where Crease add on</param>
/// <param name="point2">second point of location where Crease add on</param>
/// <returns>new created Crease</returns>
public SlabShapeCrease AddCrease(PointF point1, PointF point2)
{
//create first vertex
Transaction transaction = new Transaction(
m_commandData.Application.ActiveUIDocument.Document, "AddCrease");
transaction.Start();
Vector4 v1 = new Vector4(new Autodesk.Revit.DB.XYZ(point1.X, point1.Y, 0));
v1 = m_restoreMatrix.Transform(v1);
SlabShapeVertex vertex1 = m_slabShapeEditor.DrawPoint(new Autodesk.Revit.DB.XYZ(v1.X, v1.Y, v1.Z));
//create second vertex
Vector4 v2 = new Vector4(new Autodesk.Revit.DB.XYZ(point2.X, point2.Y, 0));
v2 = m_restoreMatrix.Transform(v2);
SlabShapeVertex vertex2 = m_slabShapeEditor.DrawPoint(new Autodesk.Revit.DB.XYZ(v2.X, v2.Y, v2.Z));
//create crease
SlabShapeCreaseArray creases = m_slabShapeEditor.DrawSplitLine(vertex1, vertex2);

SlabShapeCrease crease = creases.get_Item(0);
transaction.Commit();
//re-calculate geometry info
GetSlabProfileInfo();
return crease;
}

/// <summary>
/// judge whether point can use to create vertex on slab
/// </summary>
/// <param name="point1">location where vertex add on</param>
/// <returns>whether point can use to create vertex on slab</returns>
public bool CanCreateVertex(PointF pointF)
{
bool createSuccess = false;
Transaction transaction = new Transaction(
m_commandData.Application.ActiveUIDocument.Document, "CanCreateVertex");
transaction.Start();
Vector4 v1 = new Vector4(new Autodesk.Revit.DB.XYZ(pointF.X, pointF.Y, 0));
v1 = m_restoreMatrix.Transform(v1);
SlabShapeVertex vertex = m_slabShapeEditor.DrawPoint(new Autodesk.Revit.DB.XYZ(v1.X, v1.Y, v1.Z));
if (null != vertex) { createSuccess = true; }
transaction.RollBack();
//re-calculate geometry info
GetSlabProfileInfo();
return createSuccess;
}
}
}