应用程序名称:CurtainWallGrid
Revit 平台:所有
Revit 版本:2011.0
首次发布于:2009.0
编程语言:C#
技能级别:中等
类别:元素
类型:外部命令
主题:创建幕墙并操作其幕墙网格。
概要:
本示例演示了五个主要功能:
1. 如何根据特定的层数和墙体类型创建幕墙。
2. 如何检索幕墙的幕墙网格信息。
3. 如何编辑幕墙网格的数据。
4. 如何检索幕墙网格的网格线。
5. 如何编辑幕墙网格的网格线和格栅横梃。
项目文件:
Command.cs
该文件包含了“Command”类,该类继承自“IExternalCommand”接口,实现了“Execute”方法。
MyDocument.cs
该文件包含了“MyDocument”类,用于管理本示例中使用的所有数据。
WallGeometry.cs
包含了一个名为“WallGeometry”的类,用于管理幕墙数据。它可以创建新的幕墙,并获取幕墙的数据。
WallDrawing.cs
包含了一个名为“WallDrawing”的类,用于在画布上指定幕墙的基线。
GridGeometry.cs
包含了一个名为“GridGeometry”的类,用于管理幕墙中的幕墙网格和幕墙网格线信息。它可以检索幕墙网格和幕墙网格线的数据;也可以编辑它们的数据。
GridDrawing.cs
包含了一个名为“GridDrawing”的类,用于管理画布上幕墙网格和幕墙网格线的2D视图。
GridCoordinates.cs
包含了一个名为“GridCoordinates”的类,用于管理幕墙网格在3D和2D格式之间的变换矩阵。
MathTools.cs
包含了一个名为“MathTools”的类,用于管理变换中使用的数学类。
功能:
- 创建指定层和墙类型的幕墙。
- 检索幕墙的幕布网格。
- 检索所有幕布网格的属性。
- 检索幕布网格线并编辑它们:添加新的网格线,锁定/解锁网格线,移动网格线,添加/删除段,添加所有段。(注意:它模仿部分UI操作,如面板自动合并功能等,但仅支持简单情况。如果对幕布网格进行复杂操作,样本的外观可能与UI不同。)
- 检索所有附加的柱子并操纵它们:将柱子添加到幕布网格段中并删除幕布网格的柱子。(注意:由于Mullion类的限制,只允许将柱子添加到网格线的段中,不能将柱子添加到幕布网格的边缘。)
实现:
- 使用元素过滤器获取活动文档中的所有视图。
- 使用适当的幕墙类型通过Autodesk.Revit.Creation.Document.NewWall(Curve curve, WallType wallType, Level level, double height, double offset, bool flip, bool structural)方法创建幕墙。
- 通过CurtainGridLine AddGridLine(bool isConstVisUGridLine, Revit.Geometry.XYZ position,bool oneSegmentOnly)添加幕布网格线。
- 通过bool Move (Revit.Geometry.XYZ moveVec)移动幕布网格线。
- 通过void AddSegment(Revit.Geometry.Curve^ curve)添加一个段。
- 通过void RemoveSegment(Revit.Geometry.Curve^ curve)移除一个段。
- 通过ElementSet AddMullions(Curve segmentCurve, MullionType mullionType,bool oneSegmentOnly)添加一个柱子。
指南:
1. 打开Revit Architecture 2009并创建一个新文档。
2. 运行此命令。
3. 弹出一个“Curtain Wall”对话框,其中有2个选项卡,第一个是“Create Curtain Wall”,另一个是“Curtain Grid”,此时仅限于第一个选项卡。
4. 所有视图和墙型在两个下拉列表中列出,通过从列表中选择一个来指定它们,指定的视图和墙型将用于幕墙的创建。
5. 幕墙创建需要一个基准线。左键单击画布左侧以指定基准线。在绘制基准线时按“ESC”键停止绘制基准线。单击“清除基准线”按钮以重新绘制基准线,单击“创建幕墙”按钮以使用指定的基准线、视图和墙型创建幕墙。完成后,可以切换到“Curtain Grid”选项卡页。
6. 幕布网格的所有属性都列在右侧的属性网格中。
7. 幕墙的幕布网格在左侧的画布上绘制出来。
8. 所有支持的幕布网格和幕布网格线操作:添加水平网格线、添加竖直网格线、锁定或解锁网格线、移动网格线、添加段、删除段和添加所有段
9. 所有幕布网格和幕布网格线的操作都限制在幕布网格的边界内,这意味着鼠标指针必须移动到边界内,操作才能正常工作。
10. 连续操作:默认情况下,在一次操作完成后,操作将停止并改为“等待”。例如:在绘制一条水平网格线后,用户应该从组合框中指定另一个操作。如果用户想一次性绘制多条水平网格线,他/她应该按下“Ctrl”键并保持连续操作。例如:从下拉列表中选择“添加水平网格线”,按下“Ctrl”键,在画布上绘制一条水平线,之后用户可以在没有再次指定操作的情况下绘制另一条水平线。如果用户想停止连续操作,他/她可以释放“Ctrl”键并执行最后一个操作,在最后一个操作完成后,操作将停止并改为“等待”;他/她也可以按“ESC”键强制停止当前操作,并将操作改为“等待”。
11. 对于“添加水平网格线”,将鼠标移动到幕布网格区域内,将显示一条虚线水平网格线,它是即将添加的新水平网格线,单击左键将其添加到幕布网格中。不允许添加一个网格线重叠另一个网格线。支持Ctrl键和ESC键。
12. 对于“添加竖直网格线”,与“添加水平网格线”类似,只是虚线是竖直的。支持Ctrl键和ESC键。
13. 对于“锁定或解锁网格线”,将鼠标指针移动到网格线上悬停,网格线的锁定状态将显示为“已锁定”或“未锁定”提示,单击左键切换锁定状态,提示将更新。
14. 对于“移动网格线”,仅允许移动未锁定的网格线,因此在移动网格线之前确保网格线未锁定。单击未锁定的网格线来决定要移动哪条网格线,然后移动鼠标来决定将网格线移动到哪个位置。再次单击左键完成移动网格线。支持Ctrl键和ESC键。
15. 对于“添加段”,只允许在先前删除段的地方添加段,因此默认情况下无法执行“添加段”操作,因为还没有删除段。首先删除一些段,然后使用此操作将它们添加回去。支持Ctrl键和ESC键。
16. 对于“删除段”,一条段不允许被删除两次,这意味着我们只能删除之前没有删除的段。支持Ctrl键和ESC键。
17. 删除一个段可能会导致其他“共线-悬挂”段自动被删除。例如,在图1中,删除“段A”(水平的、红色高亮显示的段)将使“段B”(水平的、棕色的)自动被删除,因为“段B”是一条“共线-悬挂”段。
18.在“删除分段”功能和“自动删除”功能中,不允许删除窗帘网格线的最后一个分段。例如,在图2中,由于“分段B”是窗帘网格线的最后一个分段,所以不允许删除它。 在图3中,删除“分段A”将导致“分段B”成为“共线悬挂”,并尝试删除“分段B”,但是由于“分段C”已经被删除,所以“分段B”将成为其窗帘网格线的最后一个分段,所以不允许删除“分段A”。因此,也适用于“自动删除”功能。
19.在“删除分段”功能中,删除一个分段可能会自动隐藏其他“交叉悬挂”的分段。例如,在图4中,删除“分段A”会使“分段B”成为“交叉悬挂”,因此“分段B”将被标记为灰色,表明它被自动隐藏了(图5),就像Revit UI一样(在界面上,它是不可见的,只有在鼠标悬停时才会显示)。
20. “添加整个网格线的分段”功能类似于“添加分段”,只允许将此操作应用于已删除分段的网格线。支持Ctrl键和ESC键。
21. “添加所有分段的框条”功能将在窗帘网格的所有可见分段上添加框条。(注意:由于Mullion类的限制,无法在窗帘网格的边缘添加框条。)
22. “删除所有框条”功能将删除窗帘网格中的所有框条。
23. 单击任一选项卡页面中的“退出”按钮将关闭对话框。
完整的源代码请加入QQ群649037449,在群文件中下载RevitSDK.exe,解压后在文件夹中搜索本文中应用程序名称即可获得完整源码
WallGeometry.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.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace Revit.SDK.Samples.CurtainWallGrid.CS
{
/// <summary>
/// the class manages the creation operation for the curtain wall
/// </summary>
public class WallGeometry
{
#region Fields
// the document of this sample
MyDocument m_myDocument;
// the refferred drawing class for the curtain wall
private WallDrawing m_drawing;
// the selected ViewPlan used for curtain wall creation
Autodesk.Revit.DB.ViewPlan m_selectedView;
// the selected wall type
WallType m_selectedWallType;
// store the start point of baseline (in PointD format)
PointD m_startPointD;
//store the start point of baseline (in Autodesk.Revit.DB.XYZ format)
Autodesk.Revit.DB.XYZ m_startXYZ;
// store the end point of baseline (in PointD format)
PointD m_endPointD;
//store the end point of baseline (in Autodesk.Revit.DB.XYZ format)
Autodesk.Revit.DB.XYZ m_endXYZ;
#endregion
#region Properties
/// <summary>
/// the document of this sample
/// </summary>
public MyDocument MyDocument
{
get
{
return m_myDocument;
}
}
/// <summary>
/// the refferred drawing class for the curtain wall
/// </summary>
public WallDrawing Drawing
{
get
{
return m_drawing;
}
}
/// <summary>
/// the selected ViewPlan used for curtain wall creation
/// </summary>
public Autodesk.Revit.DB.ViewPlan SelectedView
{
get
{
return m_selectedView;
}
set
{
m_selectedView = value;
}
}
/// <summary>
/// the selected wall type
/// </summary>
public WallType SelectedWallType
{
get
{
return m_selectedWallType;
}
set
{
m_selectedWallType = value;
}
}
/// <summary>
/// store the start point of baseline (in PointD format)
/// </summary>
public PointD StartPointD
{
get
{
return m_startPointD;
}
set
{
m_startPointD = value;
}
}
/// <summary>
/// Get start point of baseline
/// </summary>
public Autodesk.Revit.DB.XYZ StartXYZ
{
get
{
return m_startXYZ;
}
set
{
m_startXYZ = value;
}
}
/// <summary>
/// store the end point of baseline (in PointD format)
/// </summary>
public PointD EndPointD
{
get
{
return m_endPointD;
}
set
{
m_endPointD = value;
}
}
/// <summary>
/// Get end point of baseline
/// </summary>
public Autodesk.Revit.DB.XYZ EndXYZ
{
get
{
return m_endXYZ;
}
set
{
m_endXYZ = value;
}
}
#endregion
#region Constructors
/// <summary>
/// default constructor
/// </summary>
/// <param name="myDoc">
/// the document of the sample
/// </param>
public WallGeometry(MyDocument myDoc)
{
m_myDocument = myDoc;
m_drawing = new WallDrawing(this);
}
#endregion
#region Public methods
/// <summary>
/// create the curtain wall to the active document of Revit
/// </summary>
/// <returns>
/// the created curtain wall
/// </returns>
public Wall CreateCurtainWall()
{
if (null == m_selectedWallType || null == m_selectedView)
{
return null;
}
Autodesk.Revit.Creation.Document createDoc = m_myDocument.Document.Create;
Autodesk.Revit.Creation.Application createApp = m_myDocument.CommandData.Application.Application.Create;
//baseline
System.Drawing.Point point0 = m_drawing.WallLine2D.StartPoint;
System.Drawing.Point point1 = m_drawing.WallLine2D.EndPoint;
//new baseline and transform coordinate on windows UI to Revit UI
m_startXYZ = new Autodesk.Revit.DB.XYZ(m_startPointD.X, m_startPointD.Y, 0);
m_endXYZ = new Autodesk.Revit.DB.XYZ(m_endPointD.X, m_endPointD.Y, 0);
Autodesk.Revit.DB.Line baseline = null;
try
{
baseline = Line.CreateBound(m_startXYZ, m_endXYZ);
}
catch (System.ArgumentException)
{
TaskDialog.Show("Revit", "The start point and the end point of the line are too close, please re-draw it.");
}
Transaction act = new Transaction(m_myDocument.Document);
act.Start(Guid.NewGuid().GetHashCode().ToString());
Wall wall = Wall.Create(m_myDocument.Document, baseline, m_selectedWallType.Id,
m_selectedView.GenLevel.Id, 20, 0, false, false);
act.Commit();
Transaction act2 = new Transaction(m_myDocument.Document);
act2.Start(Guid.NewGuid().GetHashCode().ToString());
m_myDocument.UIDocument.ShowElements(wall);
act2.Commit();
return wall;
}
#endregion
}// end of class
}
WallDrawing.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.Resources;
using System.Reflection;
namespace Revit.SDK.Samples.CurtainWallGrid.CS
{
/// <summary>
/// maintain the baseline of the curtain wall
/// </summary>
public class WallDrawing
{
#region Fields
// zoom the baseline to a suitable length
public double SCALEFACTOR = 5.0;
// the boundary of the canvas for the baseline drawing
Rectangle m_boundary;
// the origin for the baseline (it's the center of the canvas)
Point m_origin;
// the referred parent wall geometry
WallGeometry m_refGeometry;
// store the document of this sample
MyDocument m_myDocument;
// the font used in drawing the baseline of the curtain wall
Font m_coordinateFont;
// the baseline of the curtain wall
WallBaseline2D m_wallLine2D;
#endregion
#region Properties
/// <summary>
/// the boundary of the canvas for the baseline drawing
/// </summary>
public Rectangle Boundary
{
get
{
return m_boundary;
}
set
{
m_boundary = value;
}
}
/// <summary>
/// the origin for the baseline (it's the center of the canvas)
/// </summary>
public Point Origin
{
get
{
return m_origin;
}
set
{
m_origin = value;
}
}
/// <summary>
/// the baseline of the curtain wall
/// </summary>
public WallBaseline2D WallLine2D
{
get
{
return m_wallLine2D;
}
}
#endregion
#region Constructors
/// <summary>
/// default constructor
/// </summary>
/// <param name="wallGeo">
/// the mapped wall geometry information
/// </param>
public WallDrawing(WallGeometry wallGeo)
{
m_coordinateFont = new Font("Verdana", 10, FontStyle.Regular);
m_wallLine2D = new WallBaseline2D();
m_myDocument = wallGeo.MyDocument;
m_refGeometry = wallGeo;
}
#endregion
#region Public methods
/// <summary>
/// Add point to baseline of the curtain wall
/// </summary>
/// <param name="mousePosition">
/// the location of the mouse cursor
/// </param>
public void AddPoint(Point mousePosition)
{
// both end points of the baseline specified, can't add more points
if (Point.Empty != m_wallLine2D.StartPoint &&
Point.Empty != m_wallLine2D.EndPoint)
{
return;
}
// start point isn't specified, specify it
if (Point.Empty == m_wallLine2D.StartPoint)
{
m_wallLine2D.StartPoint = mousePosition;
m_refGeometry.StartPointD = ConvertToPointD(mousePosition);
}
// start point specified, end point isn't, so specify the end point
else if (Point.Empty == m_wallLine2D.EndPoint)
{
// don't let the length of the 2 points too small
if (Math.Abs(m_wallLine2D.StartPoint.X - mousePosition.X) >= 2 ||
Math.Abs(m_wallLine2D.StartPoint.Y - mousePosition.Y) >= 2)
{
m_wallLine2D.EndPoint = mousePosition;
m_refGeometry.EndPointD = ConvertToPointD(mousePosition);
m_wallLine2D.AssistantPoint = Point.Empty;
}
}
}
/// <summary>
/// store mouse position when mouse moves (the location will be the candidate end points of the baseline)
/// </summary>
/// <param name="mousePosition">
/// the location of the mouse cursor
/// </param>
public void AddMousePosition(Point mousePosition)
{
// both endpoints for the baseline have been confirmed, no need to record the mouse location
if (Point.Empty != m_wallLine2D.StartPoint &&
Point.Empty != m_wallLine2D.EndPoint)
{
return;
}
// we just start to draw the baseline, no end points are specified
// or just the start point was specified, so the mouse position will be the "candidate end point"
m_wallLine2D.AssistantPoint = mousePosition;
}
/// <summary>
/// draw the baseline for the curtain wall creation in the picture box
/// in the "Create Curtain Wall" tab page, user needs to draw the baseline for wall creation
/// </summary>
/// <param name="graphics">
/// form graphic
/// </param>
/// <param name="pen">
/// pen used to draw line in pictureBox
/// </param>
public void Draw(Graphics graphics, Pen pen)
{
// draw the coordinate system origin
DrawCoordinateOrigin(graphics, pen);
// draw the baseline
DrawBaseline(graphics, pen);
}
/// <summary>
/// Clear points in baseline
/// </summary>
public void RemovePoints()
{
m_wallLine2D.Clear();
}
#endregion
#region Private methods
/// <summary>
/// scale the point and store them in PointD format
/// </summary>
/// <param name="srcPoint">
/// the point to-be-zoomed
/// </param>
/// <returns>
/// the scaled result point
/// </returns>
private PointD ConvertToPointD(Point srcPoint)
{
double x = -1;
double y = -1;
x = srcPoint.X - m_origin.X;
y = m_origin.Y - srcPoint.Y;
x /= SCALEFACTOR;
y /= SCALEFACTOR;
return new PointD(x, y);
}
/// <summary>
/// draw the coordinate system origin for the baseline drawing
/// </summary>
/// <param name="graphics">
/// form graphic
/// </param>
/// <param name="pen">
/// pen used to draw line in pictureBox
/// </param>
private void DrawCoordinateOrigin(Graphics graphics, Pen pen)
{
// draw the coordinate system origin
graphics.DrawLine(pen, new Point(m_origin.X - 10, m_origin.Y), new Point(m_origin.X + 10, m_origin.Y));
graphics.DrawLine(pen, new Point(m_origin.X, m_origin.Y - 10), new Point(m_origin.X, m_origin.Y + 10));
graphics.DrawString("(0,0)", m_coordinateFont, Brushes.Blue, new PointF(m_origin.X + 2, m_origin.Y + 2));
}
/// <summary>
/// draw the baseline / the candidate baseline (start point confirmed, end point didn't)
/// </summary>
/// <param name="graphics">
/// form graphic
/// </param>
/// <param name="pen">
/// pen used to draw line in pictureBox
/// </param>
private void DrawBaseline(Graphics graphics, Pen pen)
{
if (Point.Empty != m_wallLine2D.AssistantPoint)
{
if (Point.Empty != m_wallLine2D.StartPoint)
{
graphics.DrawLine(pen, m_wallLine2D.StartPoint, m_wallLine2D.AssistantPoint);
}
// show the real-time coordinate of the mouse position
WriteCoordinate(graphics, pen);
}
if (Point.Empty != m_wallLine2D.EndPoint &&
Point.Empty != m_wallLine2D.EndPoint)
{
graphics.DrawLine(pen, m_wallLine2D.StartPoint, m_wallLine2D.EndPoint);
}
}
/// <summary>
/// write the coordinate for moving mouse
/// </summary>
/// <param name="graphics">
/// form graphic
/// </param>
/// <param name="pen">
/// pen used to draw line in pictureBox
/// </param>
private void WriteCoordinate(Graphics graphics, Pen pen)
{
PointD assistPointD = ConvertToPointD(m_wallLine2D.AssistantPoint);
double x = Unit.CovertFromAPI(m_myDocument.LengthUnitType, assistPointD.X);
double y = Unit.CovertFromAPI(m_myDocument.LengthUnitType, assistPointD.Y);
string xCoorString = Convert.ToString(Math.Round(x, 1));
string yCoorString = Convert.ToString(Math.Round(y, 1));
string unitType = Revit.SDK.Samples.CurtainWallGrid.CS.Properties.Resources.ResourceManager.GetString(m_myDocument.LengthUnitType.ToString());
String coordinate = "(" + xCoorString + unitType + "," + yCoorString + unitType + ")";
graphics.DrawString(coordinate, m_coordinateFont, Brushes.Blue,
new PointF(m_wallLine2D.AssistantPoint.X + 2, m_wallLine2D.AssistantPoint.Y + 2));
}
#endregion
}
}
GridGeometry.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.Windows.Forms;
using System.Drawing;
using System.Collections;
using System.Drawing.Drawing2D;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace Revit.SDK.Samples.CurtainWallGrid.CS
{
/// <summary>
/// manages the behaviors & operations of CurtainGrid
/// </summary>
public class GridGeometry
{
#region Fields
// the document of this sample
private MyDocument m_myDocument;
// stores the curtain grid information of the created curtain wall
private CurtainGrid m_activeGrid;
// the referred drawing class for the curtain grid
private GridDrawing m_drawing;
//object which contains reference of Revit Application
private ExternalCommandData m_commandData;
// the active document of Revit
private Document m_activeDocument;
// store the mullion type used in this sample
private MullionType m_mullionType;
// all the grid lines of U direction (in CurtainGridLine format)
private List<CurtainGridLine> m_uGridLines;
// all the grid lines of V direction (in CurtainGridLine format)
private List<CurtainGridLine> m_vGridLines;
// stores all the vertexes of the curtain grid (in Autodesk.Revit.DB.XYZ format)
private List<Autodesk.Revit.DB.XYZ> m_GridVertexesXYZ;
// stores all the properties of the curtain grid
private GridProperties m_gridProperties;
// store the grid line to be removed
private CurtainGridLine m_lineToBeMoved = null;
// store the offset to be moved for the specified grid line
private int m_moveOffset = 0;
#endregion
#region Properties
/// <summary>
/// stores the curtain grid information of the created curtain wall
/// </summary>
public CurtainGrid ActiveGrid
{
get
{
return m_activeGrid;
}
}
/// <summary>
/// the referred drawing class for the curtain grid
/// </summary>
public GridDrawing Drawing
{
get
{
return m_drawing;
}
}
/// <summary>
/// store the mullion type used in this sample
/// </summary>
public MullionType MullionType
{
get
{
return m_mullionType;
}
set
{
m_mullionType = value;
}
}
/// <summary>
/// all the grid lines of U direction (in CurtainGridLine format)
/// </summary>
public List<CurtainGridLine> UGridLines
{
get
{
return m_uGridLines;
}
}
/// <summary>
/// all the grid lines of V direction (in CurtainGridLine format)
/// </summary>
public List<CurtainGridLine> VGridLines
{
get
{
return m_vGridLines;
}
}
/// <summary>
/// stores all the vertexes of the curtain grid (in Autodesk.Revit.DB.XYZ format)
/// </summary>
public List<Autodesk.Revit.DB.XYZ> GridVertexesXYZ
{
get
{
return m_GridVertexesXYZ;
}
}
/// <summary>
/// stores all the properties of the curtain grid
/// </summary>
public GridProperties GridProperties
{
get
{
return m_gridProperties;
}
}
public CurtainGridLine LineToBeMoved
{
get
{
return m_lineToBeMoved;
}
}
/// <summary>
/// store the offset to be moved for the specified grid line
/// </summary>
public int MoveOffset
{
get
{
return m_moveOffset;
}
set
{
m_moveOffset = value;
}
}
#endregion
#region Constructors
/// <summary>
/// constructor
/// </summary>
/// <param name="myDoc">
/// the document of the sample
/// </param>
public GridGeometry(MyDocument myDoc)
{
m_myDocument = myDoc;
m_commandData = myDoc.CommandData;
m_activeDocument = myDoc.Document;
m_gridProperties = new GridProperties();
//m_activeGrid = grid;
m_drawing = new GridDrawing(myDoc, this);
m_uGridLines = new List<CurtainGridLine>();
m_vGridLines = new List<CurtainGridLine>();
m_GridVertexesXYZ = new List<Autodesk.Revit.DB.XYZ>();
}
#endregion
#region Public methods
/// <summary>
/// obtain all the properties of the curtain grid
/// </summary>
public void ReloadGridProperties()
{
if (null == m_activeGrid)
{
if (true == m_myDocument.WallCreated)
{
m_activeGrid = m_myDocument.CurtainWall.CurtainGrid;
}
else
{
return;
}
}
// horizontal grid pattern
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
switch (m_activeGrid.Grid2Justification)
{
case CurtainGridAlignType.Beginning:
m_gridProperties.HorizontalJustification = CurtainGridAlign.Beginning;
break;
case CurtainGridAlignType.Center:
m_gridProperties.HorizontalJustification = CurtainGridAlign.Center;
break;
case CurtainGridAlignType.End:
m_gridProperties.HorizontalJustification = CurtainGridAlign.End;
break;
default:
break;
}
m_gridProperties.HorizontalAngle = m_activeGrid.Grid2Angle * 180.0 / Math.PI;
m_gridProperties.HorizontalOffset = m_activeGrid.Grid2Offset;
m_gridProperties.HorizontalLinesNumber = m_activeGrid.NumULines;
// vertical grid pattern
switch (m_activeGrid.Grid1Justification)
{
case CurtainGridAlignType.Beginning:
m_gridProperties.VerticalJustification = CurtainGridAlign.Beginning;
break;
case CurtainGridAlignType.Center:
m_gridProperties.VerticalJustification = CurtainGridAlign.Center;
break;
case CurtainGridAlignType.End:
m_gridProperties.VerticalJustification = CurtainGridAlign.End;
break;
default:
break;
}
m_gridProperties.VerticalAngle = m_activeGrid.Grid1Angle * 180.0 / Math.PI;
m_gridProperties.VerticalOffset = m_activeGrid.Grid1Offset;
m_gridProperties.VerticalLinesNumber = m_activeGrid.NumVLines;
// other data
m_gridProperties.PanelNumber = m_activeGrid.NumPanels;
m_gridProperties.UnlockedPanelsNumber = m_activeGrid.GetUnlockedPanelIds().Count;
m_gridProperties.CellNumber = m_activeGrid.GetCurtainCells().Count;
if (0 != m_activeGrid.GetMullionIds().Count)
{
m_gridProperties.MullionsNumber = m_activeGrid.GetMullionIds().Count;
m_gridProperties.UnlockedmullionsNumber = m_activeGrid.GetUnlockedMullionIds().Count;
}
act.Commit();
}
/// <summary>
/// reload all the geometry data of the curtain grid (grid lines, vertexes, and convert them to 2D format)
/// </summary>
public void ReloadGeometryData()
{
if (null == m_activeGrid)
{
if (true == m_myDocument.WallCreated)
{
m_activeGrid = m_myDocument.CurtainWall.CurtainGrid;
}
else
{
return;
}
}
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
//ElementSet mullions = m_activeGrid.Mullions;
ICollection<ElementId> mullions = m_activeGrid.GetMullionIds();
act.Commit();
if (0 == mullions.Count)
{
foreach (ElementId e in mullions)
{
Mullion mullion = m_activeDocument.GetElement(e) as Mullion;
if (null != mullion)
{
m_mullionType = mullion.MullionType;
break;
}
}
}
GetULines();
GetVLines();
GetCurtainGridVertexes();
// covert those lines to 2D format
m_drawing.GetLines2D();
}
/// <summary>
/// remove the selected segment from the curtain grid
/// </summary>
public void RemoveSegment()
{
// verify that the mouse is inside the curtain grid area
List<KeyValuePair<Line2D, Pen>> lines2D = m_drawing.DrawObject.Lines2D;
if (lines2D.Count < 1)
{
return;
}
List<SegmentLine2D> toBeRemovedList = new List<SegmentLine2D>();
// check whether the deletion is valid
bool canRemove = true;
MimicRemoveSegments(ref canRemove, toBeRemovedList);
// in the "MimicRemove" process, we didn't find that we need to "Remove the last segment of the grid line"
// so the "Remove" action can go on
if (true == canRemove)
{
try
{
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
foreach (SegmentLine2D seg2D in toBeRemovedList)
{
int gridLineIndex = seg2D.GridLineIndex;
int segIndex = seg2D.SegmentIndex;
bool isUSegment = seg2D.IsUSegment;
CurtainGridLine line;
if (true == isUSegment)
{
line = m_uGridLines[gridLineIndex];
}
else
{
line = m_vGridLines[gridLineIndex];
}
Curve curve = line.AllSegmentCurves.get_Item(segIndex);
line.RemoveSegment(curve);
}
act.Commit();
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
return;
}
}
// in the "MimicRemove" process, we found that we would "Remove the last segment of the grid line"
// so the whole "Remove" action will roll back
else
{
foreach (SegmentLine2D seg2D in toBeRemovedList)
{
int gridLineIndex = seg2D.GridLineIndex;
int segIndex = seg2D.SegmentIndex;
bool isUSegment = seg2D.IsUSegment;
GridLine2D gridLine2D;
if (true == isUSegment)
{
gridLine2D = m_drawing.UGridLines2D[gridLineIndex];
}
else
{
gridLine2D = m_drawing.VGridLines2D[gridLineIndex];
}
gridLine2D.RemovedNumber--;
SegmentLine2D segLine2D = gridLine2D.Segments[segIndex];
segLine2D.Removed = false;
gridLine2D.Segments[segIndex] = segLine2D;
}
string statusMsg = "Delete this segment will make some grid lines have no existent segments.";
m_myDocument.Message = new KeyValuePair<string, bool>(statusMsg, true);
}
this.ReloadGeometryData();
m_drawing.DrawObject.Clear();
}
/// <summary>
/// add a new segment to the specified location
/// </summary>
public void AddSegment()
{
// verify that the mouse is inside the curtain grid area
List<KeyValuePair<Line2D, Pen>> lines2D = m_drawing.DrawObject.Lines2D;
if (lines2D.Count < 1)
{
return;
}
// the selected segment location is on a U grid line
if (-1 != m_drawing.SelectedUIndex)
{
CurtainGridLine line = m_uGridLines[m_drawing.SelectedUIndex];
Curve curve = line.AllSegmentCurves.get_Item(m_drawing.SelectedUSegmentIndex);
if (null != line && null != curve)
{
try
{
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
line.AddSegment(curve);
act.Commit();
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
return;
}
}
GridLine2D gridLine2D = m_drawing.UGridLines2D[m_drawing.SelectedUIndex];
gridLine2D.RemovedNumber--;
SegmentLine2D segLine2D = gridLine2D.Segments[m_drawing.SelectedUSegmentIndex];
segLine2D.Removed = false;
gridLine2D.Segments[m_drawing.SelectedUSegmentIndex] = segLine2D;
}
// the selected segment location is on a V grid line
else if (-1 != m_drawing.SelectedVIndex)
{
CurtainGridLine line = m_vGridLines[m_drawing.SelectedVIndex];
Curve curve = line.AllSegmentCurves.get_Item(m_drawing.SelectedVSegmentIndex);
if (null != line && null != curve)
{
try
{
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
line.AddSegment(curve);
act.Commit();
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
return;
}
}
GridLine2D gridLine2D = m_drawing.VGridLines2D[m_drawing.SelectedVIndex];
gridLine2D.RemovedNumber--;
SegmentLine2D segLine2D = gridLine2D.Segments[m_drawing.SelectedVSegmentIndex];
segLine2D.Removed = false;
gridLine2D.Segments[m_drawing.SelectedVSegmentIndex] = segLine2D;
}
this.ReloadGeometryData();
m_drawing.DrawObject.Clear();
}
/// <summary>
/// add all the deleted segments back for a grid line
/// </summary>
public void AddAllSegments()
{
// verify that the mouse is inside the curtain grid area
List<KeyValuePair<Line2D, Pen>> lines2D = m_drawing.DrawObject.Lines2D;
if (lines2D.Count < 1)
{
return;
}
if (-1 != m_drawing.SelectedUIndex)
{
CurtainGridLine line = m_uGridLines[m_drawing.SelectedUIndex];
if (null != line)
{
try
{
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
line.AddAllSegments();
act.Commit();
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
return;
}
}
GridLine2D gridLine2D = m_drawing.UGridLines2D[m_drawing.SelectedUIndex];
gridLine2D.RemovedNumber = 0;
foreach (SegmentLine2D segLine2D in gridLine2D.Segments)
{
segLine2D.Removed = false;
}
}
else if (-1 != m_drawing.SelectedVIndex)
{
CurtainGridLine line = m_vGridLines[m_drawing.SelectedVIndex];
if (null != line)
{
try
{
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
line.AddAllSegments();
act.Commit();
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
return;
}
}
GridLine2D gridLine2D = m_drawing.VGridLines2D[m_drawing.SelectedVIndex];
gridLine2D.RemovedNumber = 0;
foreach (SegmentLine2D segLine2D in gridLine2D.Segments)
{
segLine2D.Removed = false;
}
}
this.ReloadGeometryData();
m_drawing.DrawObject.Clear();
}
/// <summary>
/// add a new U grid line to the specified location
/// </summary>
public void AddUGridLine()
{
// verify that the mouse location is valid: it's inside the curtain grid area
// & it doesn't lap over another grid line (it's not allowed to add a grid line to lap over another one)
if (false == m_drawing.MouseLocationValid)
{
return;
}
// all the assistant lines (in "Add U (Horizontal) Grid Line" operation,
// there's only one dash line, this line indicates the location to be added)
List<KeyValuePair<Line2D, Pen>> lines2D = m_drawing.DrawObject.Lines2D;
if (lines2D.Count < 1)
{
return;
}
// the dash U line shown in the sample (incidates the location to be added)
Line2D line2D = lines2D[0].Key;
if (System.Drawing.Point.Empty == line2D.StartPoint ||
System.Drawing.Point.Empty == line2D.EndPoint)
{
return;
}
// get the point to be added
int midX = (line2D.StartPoint.X + line2D.EndPoint.X) / 2;
int midY = (line2D.StartPoint.Y + line2D.EndPoint.Y) / 2;
// transform the 2D point to Autodesk.Revit.DB.XYZ format
Autodesk.Revit.DB.XYZ pos = new Autodesk.Revit.DB.XYZ(midX, midY, 0);
Vector4 vec = new Vector4(pos);
vec = m_drawing.Coordinates.RestoreMatrix.Transform(vec);
CurtainGridLine newLine;
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
try
{
newLine = ActiveGrid.AddGridLine(true, new Autodesk.Revit.DB.XYZ(vec.X, vec.Y, vec.Z), false);
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
// "add U line" failed, so return directly
return;
}
act.Commit();
// U line added, the V line's segment information changed, so reload all the geometry data
this.ReloadGeometryData();
}
/// <summary>
/// add a new V grid line to the specified location
/// </summary>
public void AddVGridLine()
{
// verify that the mouse location is valid: it's inside the curtain grid area
// & it doesn't lap over another grid line (it's not allowed to add a grid line to lap over another one)
if (false == m_drawing.MouseLocationValid)
{
return;
}
// all the assistant lines (in "Add V (Vertical) Grid Line" operation,
// there's only one dash line, this line indicates the location to be added)
List<KeyValuePair<Line2D, Pen>> lines2D = m_drawing.DrawObject.Lines2D;
if (lines2D.Count < 1)
{
return;
}
// the dash V line shown in the sample (incidates the location to be added)
Line2D line2D = lines2D[0].Key;
if (System.Drawing.Point.Empty == line2D.StartPoint ||
System.Drawing.Point.Empty == line2D.EndPoint)
{
return;
}
// get the point to be added
int midX = (line2D.StartPoint.X + line2D.EndPoint.X) / 2;
int midY = (line2D.StartPoint.Y + line2D.EndPoint.Y) / 2;
// transform the 2D point to Autodesk.Revit.DB.XYZ format
Autodesk.Revit.DB.XYZ pos = new Autodesk.Revit.DB.XYZ(midX, midY, 0);
Vector4 vec = new Vector4(pos);
vec = m_drawing.Coordinates.RestoreMatrix.Transform(vec);
CurtainGridLine newLine;
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
try
{
newLine = ActiveGrid.AddGridLine(false, new Autodesk.Revit.DB.XYZ(vec.X, vec.Y, vec.Z), false);
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
// "add V line" failed, so return directly
return;
}
act.Commit();
// V line added, the U line's segment information changed, so reload all the geometry data
this.ReloadGeometryData();
}
/// <summary>
/// toggle the selected grid line's Lock status: if it's locked, unlock it, vice versa
/// </summary>
public void LockOrUnlockSelectedGridLine()
{
CurtainGridLine line = null;
GridLine2D line2D = new GridLine2D();
// get the selected grid line
if (-1 != m_drawing.SelectedUIndex)
{
line = m_uGridLines[m_drawing.SelectedUIndex];
line2D = m_drawing.UGridLines2D[m_drawing.SelectedUIndex];
}
else if (-1 != m_drawing.SelectedVIndex)
{
line = m_vGridLines[m_drawing.SelectedVIndex];
line2D = m_drawing.VGridLines2D[m_drawing.SelectedVIndex];
}
else
{
return;
}
// lock/unlock the grid line
if (null != line)
{
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
line.Lock = !line.Lock;
act.Commit();
}
// update the mapped line2D's data
line2D.Locked = line.Lock;
// clear the intermediate variables and instances
m_drawing.DrawObject.Clear();
}
/// <summary>
/// get the grid line to be removed
/// </summary>
/// <returns>
/// if the line obtained, return true; otherwise false
/// </returns>
public bool GetLineToBeMoved()
{
if (-1 != m_drawing.SelectedUIndex)
{
m_lineToBeMoved = m_uGridLines[m_drawing.SelectedUIndex];
return true;
}
else if (-1 != m_drawing.SelectedVIndex)
{
m_lineToBeMoved = m_vGridLines[m_drawing.SelectedVIndex];
return true;
}
else
{
m_lineToBeMoved = null;
return false;
}
}
/// <summary>
/// move the selected grid line to the location of the mouse cursor
/// </summary>
/// <param name="mousePosition">
/// indicates the destination position of the grid line
/// </param>
/// <returns>
/// return whether the grid line be moved successfully
/// </returns>
public bool MoveGridLine(System.Drawing.Point mousePosition)
{
// verify that the mouse location is valid: it's inside the curtain grid area
// & it doesn't lap over another grid line (it's not allowed to move a grid line to lap over another one)
if (false == m_drawing.MouseLocationValid)
{
return false;
}
if (null == m_lineToBeMoved)
{
return false;
}
// move a U line along the V direction
if (-1 != m_drawing.SelectedUIndex)
{
// convert the 2D data to 3D
Autodesk.Revit.DB.XYZ xyz = new Autodesk.Revit.DB.XYZ(mousePosition.X, mousePosition.Y, 0);
Vector4 vec = new Vector4(xyz);
vec = m_drawing.Coordinates.RestoreMatrix.Transform(vec);
double offset = vec.Z - m_lineToBeMoved.FullCurve.GetEndPoint(0).Z;
xyz = new Autodesk.Revit.DB.XYZ(0, 0, offset);
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
try
{
ElementTransformUtils.MoveElement(m_activeDocument, m_lineToBeMoved.Id, xyz);
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
return false;
}
act.Commit();
// update the grid line 2d
GridLine2D line = m_drawing.UGridLines2D[m_drawing.SelectedUIndex];
line.StartPoint = new System.Drawing.Point(line.StartPoint.X, line.StartPoint.Y + m_moveOffset);
line.EndPoint = new System.Drawing.Point(line.EndPoint.X, line.EndPoint.Y + m_moveOffset);
// update the mapped grid line graphics path
GraphicsPath path = new GraphicsPath();
path.AddLine(line.StartPoint, line.EndPoint);
m_drawing.ULinePathList[m_drawing.SelectedUIndex] = path;
// update the mapped segment line and its graphics path
List<GraphicsPath> pathList = m_drawing.USegLinePathListList[m_drawing.SelectedUIndex];
List<SegmentLine2D> segLineList = line.Segments;
for (int i = 0; i < segLineList.Count; i++)
{
// update the segment
SegmentLine2D segLine2D = segLineList[i];
segLine2D.StartPoint = new System.Drawing.Point(segLine2D.StartPoint.X, segLine2D.StartPoint.Y + m_moveOffset);
segLine2D.EndPoint = new System.Drawing.Point(segLine2D.EndPoint.X, segLine2D.EndPoint.Y + m_moveOffset);
// update the segment's graphics path
GraphicsPath gpath = new GraphicsPath();
path.AddLine(segLine2D.StartPoint, segLine2D.EndPoint);
pathList[i] = gpath;
}
}
// move a V line along the U direction
else if (-1 != m_drawing.SelectedVIndex)
{
// convert the 2D data to 3D
Autodesk.Revit.DB.XYZ xyz = new Autodesk.Revit.DB.XYZ(mousePosition.X, mousePosition.Y, 0);
Vector4 vec = new Vector4(xyz);
vec = m_drawing.Coordinates.RestoreMatrix.Transform(vec);
double offset = vec.X - m_lineToBeMoved.FullCurve.GetEndPoint(0).X;
xyz = new Autodesk.Revit.DB.XYZ(offset, 0, 0);
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
try
{
ElementTransformUtils.MoveElement(m_activeDocument, m_lineToBeMoved.Id, xyz);
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
return false;
}
act.Commit();
// update the grid line 2d
GridLine2D line = m_drawing.VGridLines2D[m_drawing.SelectedVIndex];
line.StartPoint = new System.Drawing.Point(line.StartPoint.X + m_moveOffset, line.StartPoint.Y);
line.EndPoint = new System.Drawing.Point(line.EndPoint.X + m_moveOffset, line.EndPoint.Y);
// update the mapped grid line graphics path
GraphicsPath path = new GraphicsPath();
path.AddLine(line.StartPoint, line.EndPoint);
m_drawing.VLinePathList[m_drawing.SelectedVIndex] = path;
// update the mapped segment line and its graphics path
List<GraphicsPath> pathList = m_drawing.VSegLinePathListList[m_drawing.SelectedVIndex];
List<SegmentLine2D> segLineList = line.Segments;
for (int i = 0; i < segLineList.Count; i++)
{
// update the segment
SegmentLine2D segLine2D = segLineList[i];
segLine2D.StartPoint = new System.Drawing.Point(segLine2D.StartPoint.X + m_moveOffset, segLine2D.StartPoint.Y);
segLine2D.EndPoint = new System.Drawing.Point(segLine2D.EndPoint.X + m_moveOffset, segLine2D.EndPoint.Y);
// update the segment's graphics path
GraphicsPath gpath = new GraphicsPath();
path.AddLine(segLine2D.StartPoint, segLine2D.EndPoint);
pathList[i] = gpath;
}
}
// line moved, the segment information changed, so reload all the geometry data
this.ReloadGeometryData();
m_drawing.DrawObject.Clear();
return true;
}
/// <summary>
/// add mullions to all the segments of the curtain grid
/// due to the limitations of Mullions, it's not available yet to add mullions to the
/// edges of the curtain grid as Revit UI does
/// </summary>
public void AddAllMullions()
{
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
try
{
// add mullions to all U grid lines
foreach (CurtainGridLine line in m_uGridLines)
{
line.AddMullions(line.AllSegmentCurves.get_Item(0), m_mullionType, false);
}
// add mullions to all V grid lines
foreach (CurtainGridLine line in m_vGridLines)
{
line.AddMullions(line.AllSegmentCurves.get_Item(0), m_mullionType, false);
}
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
return;
}
act.Commit();
}
/// <summary>
/// delete all the mullions of the curtain grid
/// </summary>
public void DeleteAllMullions()
{
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
try
{
ICollection<ElementId> mullions = m_activeGrid.GetMullionIds();
foreach (ElementId e in mullions)
{
Mullion mullion = m_activeDocument.GetElement(e) as Mullion;
// Exceptions may jump out if attempting to delete "Locked" mullions
if (true == mullion.Lockable && true == mullion.Lock)
{
mullion.Lock = false;
}
m_activeDocument.Delete(mullion.Id);
}
}
catch (System.Exception e)
{
TaskDialog.Show("Exception", e.Message);
return;
}
act.Commit();
}
#endregion
#region Private methods
/// <summary>
/// get all the U grid lines' data of the curtain grid
/// </summary>
private void GetULines()
{
m_uGridLines.Clear();
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
//ElementSet uLines = m_activeGrid.UGridLines;
ICollection<ElementId> uLines = m_activeGrid.GetUGridLineIds();
act.Commit();
if (0 == uLines.Count)
{
return;
}
foreach (ElementId e in uLines)
{
CurtainGridLine line = m_activeDocument.GetElement(e) as CurtainGridLine;
m_uGridLines.Add(line);
}
}
/// <summary>
/// get all the V grid lines' data of the curtain grid
/// </summary>
private void GetVLines()
{
m_vGridLines.Clear();
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
//ElementSet vLines = m_activeGrid.VGridLines;
ICollection<ElementId> vLines = m_activeGrid.GetVGridLineIds();
act.Commit();
if (0 == vLines.Count)
{
return;
}
foreach (ElementId e in vLines)
{
CurtainGridLine line = m_activeDocument.GetElement(e) as CurtainGridLine;
m_vGridLines.Add(line);
}
}
/// <summary>
/// get all of the 4 vertexes of the curtain grid
/// </summary>
/// <returns></returns>
private bool GetCurtainGridVertexes()
{
// even in "ReloadGeometryData()" method, no need to reload the boundary information
// (as the boundary of the curtain grid won't be changed in the sample)
// just need to load it after the curtain wall been created
if (null != m_GridVertexesXYZ && 0 < m_GridVertexesXYZ.Count)
{
return true;
}
// the curtain grid is from "Curtain Wall: Curtain Wall 1" (by default, the "Curtain Wall 1" has no U/V grid lines)
if (m_uGridLines.Count <= 0 || m_vGridLines.Count <= 0)
{
// special handling for "Curtain Wall: Curtain Wall 1"
// as the "Curtain Wall: Curtain Wall 1" has no U/V grid lines, so we can't compute the boundary from the grid lines
// as that kind of curtain wall contains only one curtain cell
// so we compute the boundary from the data of the curtain cell
// Obtain the geometry information of the curtain wall
// also works with some curtain grids with only U grid lines or only V grid lines
Transaction act = new Transaction(m_activeDocument, Guid.NewGuid().GetHashCode().ToString());
act.Start();
ICollection<CurtainCell> cells = m_activeGrid.GetCurtainCells();
act.Commit();
Autodesk.Revit.DB.XYZ minXYZ = new Autodesk.Revit.DB.XYZ(Double.MaxValue, Double.MaxValue, Double.MaxValue);
Autodesk.Revit.DB.XYZ maxXYZ = new Autodesk.Revit.DB.XYZ(Double.MinValue, Double.MinValue, Double.MinValue);
GetVertexesByCells(cells, ref minXYZ, ref maxXYZ);
// move the U & V lines to the boundary of the curtain grid, and get their end points as the vertexes of the curtain grid
m_GridVertexesXYZ.Add(new Autodesk.Revit.DB.XYZ(minXYZ.X, minXYZ.Y, minXYZ.Z));
m_GridVertexesXYZ.Add(new Autodesk.Revit.DB.XYZ(maxXYZ.X, maxXYZ.Y, minXYZ.Z));
m_GridVertexesXYZ.Add(new Autodesk.Revit.DB.XYZ(maxXYZ.X, maxXYZ.Y, maxXYZ.Z));
m_GridVertexesXYZ.Add(new Autodesk.Revit.DB.XYZ(minXYZ.X, minXYZ.Y, maxXYZ.Z));
return true;
}
else
{
// handling for the other kinds of curtain walls (contains U&V grid lines by default)
CurtainGridLine uLine = m_uGridLines[0];
CurtainGridLine vLine = m_vGridLines[0];
List<Autodesk.Revit.DB.XYZ> points = new List<Autodesk.Revit.DB.XYZ>();
Autodesk.Revit.DB.XYZ uStartPoint = uLine.FullCurve.GetEndPoint(0);
Autodesk.Revit.DB.XYZ uEndPoint = uLine.FullCurve.GetEndPoint(1);
Autodesk.Revit.DB.XYZ vStartPoint = vLine.FullCurve.GetEndPoint(0);
Autodesk.Revit.DB.XYZ vEndPoint = vLine.FullCurve.GetEndPoint(1);
points.Add(uStartPoint);
points.Add(uEndPoint);
points.Add(vStartPoint);
points.Add(vEndPoint);
//move the U & V lines to the boundary of the curtain grid, and get their end points as the vertexes of the curtain grid
m_GridVertexesXYZ.Add(new Autodesk.Revit.DB.XYZ(uStartPoint.X, uStartPoint.Y, vStartPoint.Z));
m_GridVertexesXYZ.Add(new Autodesk.Revit.DB.XYZ(uEndPoint.X, uEndPoint.Y, vStartPoint.Z));
m_GridVertexesXYZ.Add(new Autodesk.Revit.DB.XYZ(uEndPoint.X, uEndPoint.Y, vEndPoint.Z));
m_GridVertexesXYZ.Add(new Autodesk.Revit.DB.XYZ(uStartPoint.X, uStartPoint.Y, vEndPoint.Z));
return true;
}
}
/// <summary>
/// get all the vertexes of the curtain cells
/// </summary>
/// <param name="cells">
/// the curtain cells which need to be got the vertexes
/// </param>
/// <returns>
/// the vertexes of the curtain cells
/// </returns>
private List<Autodesk.Revit.DB.XYZ> GetPoints(ICollection<CurtainCell> cells)
{
List<Autodesk.Revit.DB.XYZ> points = new List<Autodesk.Revit.DB.XYZ>();
if (null == cells || cells.Count == 0)
{
return points;
}
foreach (CurtainCell cell in cells)
{
if (null == cell || 0 == cell.CurveLoops.Size)
{
continue;
}
CurveArray curves = cell.CurveLoops.get_Item(0);
foreach (Curve curve in curves)
{
points.Add(curve.GetEndPoint(0));
points.Add(curve.GetEndPoint(1));
}
}
return points;
}
/// <summary>
/// get a bounding box which covers all the input points
/// </summary>
/// <param name="points">
/// the source points
/// </param>
/// <param name="minXYZ">
/// one of the bounding box points
/// </param>
/// <param name="maxXYZ">
/// one of the bounding box points
/// </param>
private void GetVertexesByPoints(List<Autodesk.Revit.DB.XYZ> points, ref Autodesk.Revit.DB.XYZ minXYZ, ref Autodesk.Revit.DB.XYZ maxXYZ)
{
if (null == points || 0 == points.Count)
{
return;
}
double minX = minXYZ.X;
double minY = minXYZ.Y;
double minZ = minXYZ.Z;
double maxX = maxXYZ.X;
double maxY = maxXYZ.Y;
double maxZ = maxXYZ.Z;
foreach (Autodesk.Revit.DB.XYZ xyz in points)
{
// compare the values and update the min and max value
if (xyz.X < minX)
{
minX = xyz.X;
minY = xyz.Y;
}
if (xyz.X > maxX)
{
maxX = xyz.X;
maxY = xyz.Y;
}
if (xyz.Z < minZ)
{
minZ = xyz.Z;
}
if (xyz.Z > maxZ)
{
maxZ = xyz.Z;
}
} // end of loop
minXYZ = new Autodesk.Revit.DB.XYZ(minX, minY, minZ);
maxXYZ = new Autodesk.Revit.DB.XYZ(maxX, maxY, maxZ);
}
/// <summary>
/// get the vertexes of the bounding box which covers all the curtain cells
/// </summary>
/// <param name="cells">
/// the source curtain cells
/// </param>
/// <param name="minXYZ">
/// the result bounding point
/// </param>
/// <param name="maxXYZ">
/// the result bounding point
/// </param>
private void GetVertexesByCells(ICollection<CurtainCell> cells, ref Autodesk.Revit.DB.XYZ minXYZ, ref Autodesk.Revit.DB.XYZ maxXYZ)
{
if (null == cells || cells.Count == 0)
{
return;
}
List<Autodesk.Revit.DB.XYZ> points = GetPoints(cells);
GetVertexesByPoints(points, ref minXYZ, ref maxXYZ);
}
/// <summary>
/// a simulative "Delete Segment" operation before real deletion
/// as we may occur some situations that prevent us to delete the specific segment
/// for example, delete the specific segment will make some other segments to be deleted automatically (the "conjoint" ones)
/// and the "automatically deleted" segment is the last segment of its parent grid line
/// in this situation, we should prevent deleting that specific segment and rollback all the simulative deletion
/// </summary>
/// <param name="removeList">
/// the refferred to-be-removed list, in the simulative deletion operation, all the suitable (not the last segment) segments will
/// be added to that list
/// </param>
private void MimicRemoveSegments(ref bool canRemove, List<SegmentLine2D> removeList)
{
// the currently operated is a U segment
if (-1 != m_drawing.SelectedUIndex)
{
GridLine2D gridLine2D = m_drawing.UGridLines2D[m_drawing.SelectedUIndex];
SegmentLine2D segLine2D = gridLine2D.Segments[m_drawing.SelectedUSegmentIndex];
// the to-be-deleted segment is the last one of the grid line, it's not allowed to delete it
int existingNumber = gridLine2D.Segments.Count - gridLine2D.RemovedNumber;
if (1 == existingNumber)
{
canRemove = false;
return;
}
// simulative deletion
gridLine2D.RemovedNumber++;
segLine2D.Removed = true;
gridLine2D.Segments[m_drawing.SelectedUSegmentIndex] = segLine2D;
removeList.Add(segLine2D);
// the "regeneration" step: if there're only 2 segments existing in one joint and they're in the same line, delete one seg will cause the other
// been deleted automatically
MimicRecursiveDelete(ref canRemove, segLine2D, removeList);
}
// the currently operated is a V segment
else if (-1 != m_drawing.SelectedVIndex)
{
GridLine2D gridLine2D = m_drawing.VGridLines2D[m_drawing.SelectedVIndex];
SegmentLine2D segLine2D = gridLine2D.Segments[m_drawing.SelectedVSegmentIndex];
int existingNumber = gridLine2D.Segments.Count - gridLine2D.RemovedNumber;
// the to-be-deleted segment is the last one of the grid line, it's not allowed to delete it
if (1 == existingNumber)
{
canRemove = false;
return;
}
// simulative deletion
gridLine2D.RemovedNumber++;
segLine2D.Removed = true;
gridLine2D.Segments[m_drawing.SelectedVSegmentIndex] = segLine2D;
removeList.Add(segLine2D);
// the "regeneration" step: if there're only 2 segments existing in one joint and they're in the same line, delete one seg will cause the other
// been deleted automatically
MimicRecursiveDelete(ref canRemove, segLine2D, removeList);
}
}
/// <summary>
/// the "regeneration" step: if there're only 2 segments existing in one joint and they're in the same line,
/// delete one seg will cause the other been deleted automatically
/// </summary>
/// <param name="segLine2D">
/// the to-be-automatically-deleted segment
/// </param>
/// <param name="removeList">
/// the referred to-be-deleted list of the segments
/// </param>
/// <returns>
/// returns the operation result: if there's no "last" segment in the deletion operation, return true; otherwise false
/// </returns>
private void MimicRecursiveDelete(ref bool canRemove, SegmentLine2D segLine2D, List<SegmentLine2D> removeList)
{
// the "regeneration" step: if there're only 2 segments existing in one joint
// and they're in the same line, delete one seg will cause the other
// been deleted automatically
// get conjoint U line segments
List<SegmentLine2D> removeSegments = new List<SegmentLine2D>();
m_drawing.GetConjointSegments(segLine2D, removeSegments);
// there's no isolated segment need to be removed automatically
if (null == removeSegments || 0 == removeSegments.Count)
{
// didn't "remove last segment of the curtain grid line", all the operations are valid. so return true
return;
}
// there're conjoint segments need to be removed automatically
// add the segments to removeList first, and compute whether other segments need to be
// removed automatically because of the deletion of this newly removed segment
if (true == segLine2D.Removed)
{
foreach (SegmentLine2D seg in removeSegments)
{
MimicRemoveSegment(ref canRemove, seg, removeList);
if (false == canRemove)
{
return;
}
// recursive calling
MimicRecursiveDelete(ref canRemove, seg, removeList);
}
}
}
/// <summary>
/// remove the segment from the grid line
/// </summary>
/// <param name="canRemove">
/// the returned result value, indicates whether the segment can be removed (is NOT the last segment)
/// </param>
/// <param name="seg">
/// the to-be-removed segment
/// </param>
/// <param name="removeList">
/// the referred to-be-deleted list of the segments
/// </param>
private void MimicRemoveSegment(ref bool canRemove, SegmentLine2D seg, List<SegmentLine2D> removeList)
{
int gridLineIndex = seg.GridLineIndex;
int segIndex = seg.SegmentIndex;
if (-1 != gridLineIndex && -1 != segIndex)
{
// update the gridline2d and segmentline2d data
GridLine2D grid;
if (true == seg.IsUSegment)
{
grid = m_drawing.UGridLines2D[gridLineIndex];
}
else
{
grid = m_drawing.VGridLines2D[gridLineIndex];
}
// the last segment of the grid line
int existingNumber = grid.Segments.Count - grid.RemovedNumber;
if (1 == existingNumber)
{
canRemove = false;
return;
}
grid.RemovedNumber++;
SegmentLine2D seg2D = grid.Segments[segIndex];
seg2D.Removed = true;
grid.Segments[segIndex] = seg2D;
removeList.Add(seg2D);
}
}
#endregion
}// end of class
}
GridCoordinates.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.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace Revit.SDK.Samples.CurtainWallGrid.CS
{
/// <summary>
/// Maintain the matrixes needed by 3D & 2D operations: pan, zoom, 2D->3D, 3D->2D
/// </summary>
public class GridCoordinates
{
#region Fields
// scale the size of the image to let it shown in the canvas
private float m_scaleFactor = 0.85f;
// the document of this sample
private MyDocument m_myDocument;
// stores the current GridDrawing data
private GridDrawing m_drawing;
// stores the client rectangle of the canvas of the curtain grid
// will be used in the scale matrix and move-to-center matrix
private System.Drawing.Rectangle m_boundary;
// stores the midpoint of the client rectangle
// will be used in the scale matrix and move-to-center matrix
private System.Drawing.Point m_center;
// store the Matrix used to transform 3D points to 2D
Matrix4 m_to2DMatrix = null;
// store the Matrix used to move points to center
Matrix4 m_moveToCenterMatrix = null;
// store the Matrix used to scale profile fit to pictureBox
Matrix4 m_scaleMatrix = null;
// store the Matrix used to transform Revit coordinate to window UI
Matrix4 m_transformMatrix = null;
// store the Matrix used to transform window UI coordinate to Revit
Matrix4 m_restoreMatrix = null;
// stores the boundary of the curtain grid
List<PointF> m_boundPoints;
#endregion
#region Properties
/// <summary>
/// stores the GridDrawing data used in the current dialog
/// </summary>
public GridDrawing Drawing
{
get
{
return m_drawing;
}
set
{
m_drawing = value;
}
}
/// <summary>
/// store the Matrix used to transform 3D points to 2D
/// </summary>
public Matrix4 To2DMatrix
{
get
{
return m_to2DMatrix;
}
}
/// <summary>
/// store the Matrix used to transform Revit coordinate to window UI
/// </summary>
public Matrix4 TransformMatrix
{
get
{
return m_transformMatrix;
}
}
/// <summary>
/// store the Matrix used to transform window UI coordinate to Revit
/// </summary>
public Matrix4 RestoreMatrix
{
get
{
return m_restoreMatrix;
}
}
#endregion
#region Constructors
/// <summary>
/// constructor
/// </summary>
/// <param name="myDoc">
/// the document of this sample
/// </param>
/// <param name="drawing">
/// the GridDrawing data used in the dialog
/// </param>
public GridCoordinates(MyDocument myDoc, GridDrawing drawing)
{
m_myDocument = myDoc;
if (null == drawing)
{
TaskDialog.Show("Revit", "Error! There's no grid information in the curtain wall.");
}
m_drawing = drawing;
drawing.Coordinates = this;
}
#endregion
#region Public Methods
/// <summary>
/// obtain the matrixes used in this dialog
/// </summary>
public void GetMatrix()
{
// initialize the class members, obtain the location information of the canvas
m_boundary = m_drawing.Boundary;
m_center = m_drawing.Center;
// Get a matrix which can transform points to 2D
m_to2DMatrix = GetTo2DMatrix();
// get the vertexes of the canvas (in Point/PointF format)
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();
// transform 3D points to 2D
m_transformMatrix = Get3DTo2DMatrix();
// transform from 2D to 3D
m_restoreMatrix = Get2DTo3DMatrix();
}
#endregion
#region Private Methods
/// <summary>
/// calculate the matrix used to transform 2D to 3D
/// </summary>
/// <returns>
/// matrix used to transform 2d points to 3d
/// </returns>
private Matrix4 Get2DTo3DMatrix()
{
Matrix4 matrix = Matrix4.Multiply(
new Matrix4(new Vector4(-m_center.X, -m_center.Y, 0)), m_scaleMatrix.Inverse());
matrix = Matrix4.Multiply(
matrix, m_moveToCenterMatrix);
return Matrix4.Multiply(matrix, m_to2DMatrix);
}
/// <summary>
/// calculate the matrix used to transform 3D to 2D
/// </summary>
/// <returns>
/// matrix used to transform 3d points to 2d
/// </returns>
private Matrix4 Get3DTo2DMatrix()
{
Matrix4 result = Matrix4.Multiply(
m_to2DMatrix.Inverse(), m_moveToCenterMatrix.Inverse());
result = Matrix4.Multiply(result, m_scaleMatrix);
return Matrix4.Multiply(result, new Matrix4(new Vector4(m_center.X, m_center.Y, 0)));
}
/// <summary>
/// calculate the matrix used to scale
/// </summary>
/// <returns>
/// matrix used to scale the to-be-painted image
/// </returns>
private Matrix4 GetScaleMatrix()
{
float xScale = m_boundary.Width / (m_boundPoints[1].X - m_boundPoints[0].X);
float yScale = m_boundary.Height / (m_boundPoints[1].Y - m_boundPoints[0].Y);
float factor = xScale <= yScale ? xScale : yScale;
return new Matrix4((float)(factor * m_scaleFactor));
}
/// <summary>
/// Get a matrix which can move points to center
/// </summary>
/// <returns>
/// matrix used to move point to center of canvas
/// </returns>
private Matrix4 GetMoveToCenterMatrix()
{
//translate the origin to bound center
PointF min = m_boundPoints[0];
PointF max = m_boundPoints[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 max and min coordinates of all points
/// </summary>
/// <returns>
/// points array stores the bounding box of all points
/// </returns>
private List<PointF> GetBoundsPoints()
{
Matrix4 matrix = m_to2DMatrix;
Matrix4 inverseMatrix = matrix.Inverse();
float minX = 0, maxX = 0, minY = 0, maxY = 0;
bool bFirstPoint = true;
List<PointF> resultPoints = new List<PointF>();
//get the max and min point on the face
foreach (Autodesk.Revit.DB.XYZ point in m_drawing.Geometry.GridVertexesXYZ)
{
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; }
}
}
resultPoints.Add(new PointF(minX, minY));
resultPoints.Add(new PointF(maxX, maxY));
return resultPoints;
}
/// <summary>
/// Get a matrix which can transform points to 2D
/// </summary>
/// <returns>
/// matrix which can transform points to 2D
/// </returns>
private Matrix4 GetTo2DMatrix()
{
Autodesk.Revit.DB.XYZ startXYZ = m_myDocument.WallGeometry.StartXYZ;
Autodesk.Revit.DB.XYZ endXYZ = m_myDocument.WallGeometry.EndXYZ;
XYZ sub = endXYZ - startXYZ;
Vector4 xAxis = new Vector4(new Autodesk.Revit.DB.XYZ(sub.X, sub.Y, sub.Z));
xAxis.Normalize();
//because in the windows UI, Y axis is downward
Vector4 yAxis = new Vector4(new Autodesk.Revit.DB.XYZ(0, 0, -1));
yAxis.Normalize();
Vector4 zAxis = Vector4.CrossProduct(xAxis, yAxis);
zAxis.Normalize();
Vector4 origin = new Vector4(m_drawing.Geometry.GridVertexesXYZ[0]);
return new Matrix4(xAxis, yAxis, zAxis, origin);
}
#endregion
} // end of class
}
版权所有 :无锡模信建筑科技有限公司 苏ICP备2021028830号-1 BIM建模|BIM技术应用|BIM软件开发
联系地址:江苏省无锡市新吴区龙山路4号B座705 手机:18761516598