Revit model viewer for iOS - part 1

原文链接:Revit model viewer for iOS - part 1

By Adam Nagy

In preparation for our DevCamp's we looked into what sort of demo applications we could prepare that would show examples of how to take advantage of Cloud and Mobile technologies in context of Autodesk products.

My colleague, Philippe, already created an Inventor file viewer for Android, so I had a look at that thinking about writing a similar solution for Revit with a viewer on iOS. His solution includes an Inventor AddIn that can upload Inventor files to a custom web service, which on request from a mobile client can generate the geometrical information from an Inventor file using Inventor Apprentice, and then pass it back to the mobile device that renders the geometry using OpenGL ES.

There will be some differences in our case though:

  1. There is no publicly available technology like Inventor Apprentice for Revit, so we'll have to retrieve the geometry from the model inside the Revit Add-In
  2. The geometry data we get back from Revit is organized differently from Inventor
  3. iOS 5 introduced GLKit, so I was interested in using that instead of solely relying on OpenGL function calls

My solution includes the following:

  1. A Revit AddIn that gets all the geometrical information (facets) from the model and uploads that to the Cloud - in this case to my Amazon Simple Storage Service (S3) account. Just to keep things simple the format of the data will be proprietary - it will simply contain a list of the coordinates of all the facet triangles. I chose Amazon S3 because this seemed to have really good toolkits for both iOS and .NET, the two platforms I will be using.
  2. An iOS application that accesses the data from the cloud storage and displays it using OpenGL ES

The Revit AddIn part

For easy access to the Amazon service I installed the AWS .NET SDK:http://aws.amazon.com/sdkfornet/ 
Inside my project I just needed to add a reference toC:\Program Files\AWS SDK for .NET\bin\AWSSDK.dll and then I could start accessing the cloud storage. Here is the function that uploads the data that we gather from the Revit model to the storage service - you just need to replace kAccessKey andkSecretAccessKey with your own keys:

Private Const kAccessKey As String = ""

Private Const kSecretAccessKey As String = ""

Private Const kBucketName As String = "RevitModelViewer"

 

Private Function UploadToAmazon(

ByVal memoryStream As MemoryStreamAs Boolean

 

  Using client As AmazonS3 =

    Amazon.AWSClientFactory.CreateAmazonS3Client(

      kAccessKey, kSecretAccessKey)

 

    Try

      Dim bucketRequest As New PutBucketRequest

      bucketRequest.WithBucketName(kBucketName)

 

      Using response As S3Response = client.PutBucket(bucketRequest)

      End Using

 

      Dim objectRequest As New PutObjectRequest

      objectRequest.WithBucketName(kBucketName)

      objectRequest.WithInputStream(memoryStream)

      objectRequest.WithKey(mDoc.Title)

 

      Using response As S3Response = client.PutObject(objectRequest)

      End Using

    Catch ex As AmazonS3Exception

      MessageBox.Show(ex.Message, "Model Uploader")

 

      Return False

    End Try

  End Using

 

  Return True

 

End Function

Revit SDK already contains a sample that gathers geometrical information from the model and displays it in a custom dialog:<Revit SDK>\Samples\Viewers\ElementViewer. I modified it to only collect solid geometry and then instead of showing it in our dialog it uploads the data to the cloud storage.

In this case we do not even need the transformation functions since we can simply use the model space coordinates. 

The geometrical information will be stored on a per face basis as the color can change at that level. Inside each Face section we will list all facets of the face with their coordinates - 3 coordinates and the corresponding normal vector which will be needed by OpenGL. We will calculate the normal vector from the coordinates of the 3 vertices.
>>>>>
Face;<red>, <green>, <blue>
<x1>, <y1>, <z1>;<x2>, <y2>, <z2>;<x3>, <y3>, <z3>;<xn>, <yn>, <zn>
etc.
<<<<< 

Private mOptions As Options

Private mApplication _

  As Autodesk.Revit.ApplicationServices.Application

Private mSolidCounter As Long

Private mFaceCounter As Long

Private mDoc As Document

Private mFile As TextWriter

 

Public Function Execute( _

ByVal commandData As ExternalCommandDataByRef message As String, _

ByVal elements As ElementSet) _

As Result Implements IExternalCommand.Execute

 

  ' Initialize global variables

  mApplication = commandData.Application.Application

  mDoc = commandData.Application.ActiveUIDocument.Document

  mOptions = _

    commandData.Application.Application.Create.NewGeometryOptions

  mOptions.DetailLevel = ViewDetailLevel.Fine

  mSolidCounter = 0

  mFaceCounter = 0

 

  ' Collect all the solids in the model

  Using ms As New MemoryStream

    Using textFile As TextWriter = New StreamWriter(ms)

 

      mFile = textFile

 

      For Each elem As Element In GetAllModelElements(mDoc)

        DrawElement(elem)

      Next

 

      textFile.Flush()

 

      If Not UploadToAmazon(ms) Then mSolidCounter = -1

 

    End Using

  End Using

 

  mApplication = Nothing

 

  ' Show result

  If mSolidCounter >= 0 Then

    MessageBox.Show(

      "File """ + mDoc.Title + """ with " +

      mSolidCounter.ToString() + " solids having " +

      mFaceCounter.ToString() + " faces has been uploaded " +

      "to the Cloud",

      "Model Uploader")

  End If

 

  Return Result.Succeeded

 

End Function

 

Private Function GetAllModelElements(ByVal doc As Document) _

As IList(Of Element)

 

  Dim elements As New List(Of Element)()

 

  Dim collector As FilteredElementCollector = _

    New FilteredElementCollector(doc).WhereElementIsNotElementType()

 

  For Each e As Element In collector

    If e.Category IsNot Nothing Then

      elements.Add(e)

    End If

  Next

 

  Return elements

 

End Function

 

Private Sub DrawElement(ByVal elem As Element)

 

  If TypeOf elem Is Group Then

    Dim group As Group = elem

    Dim memberIds As IList(Of ElementId) = group.GetMemberIds()

 

    For Each id As ElementId In memberIds

      Dim elm As Element = mDoc.GetElement(id)

      DrawElement(elem)

    Next

  Else

    Dim geom As GeometryElement = elem.Geometry(mOptions)

    If Not (geom Is NothingThen

      ' If a family instance then we need the version

      ' that is transformed into the model space

      If TypeOf elem Is FamilyInstance Then geom = _

        geom.GetTransformed(Transform.Identity)

 

      DrawElement(geom)

    End If

 

  End If

 

End Sub

 

Private Sub DrawElement(ByVal elementGeom As GeometryElement)

 

  If elementGeom Is Nothing Then

    Exit Sub

  End If

 

  Dim geomObject As GeometryObject

 

  For Each geomObject In elementGeom

    If (TypeOf geomObject Is GeometryInstanceThen

      DrawInstance(geomObject)

    ElseIf (TypeOf geomObject Is SolidThen

      DrawSolid(geomObject)

    End If

  Next

 

End Sub

 

Private Sub DrawInstance(ByVal geomInstance As GeometryInstance)

 

  Dim geomSymbol As GeometryElement

  geomSymbol = geomInstance.SymbolGeometry

 

  If Not (geomSymbol Is NothingThen

    DrawElement(geomSymbol)

  End If

 

End Sub

 

Private Function XyzToString(ByVal pt As XYZAs String

 

  Return (

      pt.X.ToString(CultureInfo.InvariantCulture) + ", " +

      pt.Y.ToString(CultureInfo.InvariantCulture) + ", " +

      pt.Z.ToString(CultureInfo.InvariantCulture))

 

End Function

 

Private Sub DrawMesh(ByVal geomMesh As Mesh)

 

  Dim i As Integer

 

  For i = 0 To geomMesh.NumTriangles - 1

    Dim triangle As MeshTriangle

    triangle = geomMesh.Triangle(i)

 

    ' Calculate normal

    Dim u As XYZ = triangle.Vertex(1).Subtract(triangle.Vertex(0))

    Dim v As XYZ = triangle.Vertex(2).Subtract(triangle.Vertex(0))

    Dim n As XYZ = u.CrossProduct(v).Normalize()

 

    mFile.WriteLine("{0};{1};{2};{3}",

      XyzToString(triangle.Vertex(0)),

      XyzToString(triangle.Vertex(1)),

      XyzToString(triangle.Vertex(2)),

      XyzToString(n))

  Next

 

End Sub

 

Private Sub DrawSolid(ByVal geomSolid As Solid)

 

  If geomSolid.Faces.Size > 0 Then

    Dim face As Face

    For Each face In geomSolid.Faces

      DrawFace(face)

    Next

 

    mSolidCounter += 1

  End If

 

End Sub

 

Private Sub DrawFace(ByVal geomFace As Face)

 

  Dim mat As Material = mDoc.GetElement(geomFace.MaterialElementId)

  Dim col As Color = New Color(128, 128, 128)

 

  If mat IsNot Nothing Then col = mat.Color

 

  mFile.WriteLine( _

    "Face;{0}, {1}, {2}", col.Red, col.Green, col.Blue)

 

  DrawMesh(geomFace.Triangulate)

 

  mFaceCounter += 1

 

End Sub

The Revit AddIn part is done - you can download it from here: Download RevitModelViewer - Revit AddIn - 2012-06-19

Once you compiled the project and set it up according to the readme.txt file so that it gets automatically loaded into Revit, then you can just open up any project and run the command from the Ribbon, Add-Ins tab >> External Tools >> Model Uploader. If the upload succeeds then you'll see a message like this:

Modeluploader

The AWS .NET SDK also includes a Visual Studio Add-In that makes it quite easy to check the uploaded content:

AWS Explorer

In the next post we will look at implementing the iOS model viewer application.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值