创建Multipatch三维图形

创建Multipatch三维图形
Multipatch对象学习,3D建模
Multipatch是一系列几何对象组成的 可以表示3D效果的对象实体。
其中组成Multipatch的几何对象大致可以分为以下几种:
1,三角带;2,三角扇形;3,环状(内环和外环);
通过IMultipatch接口可以控制并创建一个Multipatch对象,这个接口提供了多种具体的方法和实现属性;
同时也可以使用IConstructMultiPatch接口来进行Multipatch的创建工作,
如下六个方法依据不同的方式进行创建Multipatch(Extrude为压缩的意思):
ConstructExtrude  
ConstructExtrudeAbsolute
ConstructExtrudeAlongLine
ConstructExtrudeBetween
ConstructExtrudeFromTo
ConstructExtrudeRelative
IGeneralMultiPatchCreator这个接口是用来创建具有纹理信息的Multipatch对象的,也就是所谓的textured纹理Multipatch对象;
当依据上述接口、方法创建完Multipatch后,可以使用IGeneralMultiPatchInfo 接口来对所创建的Multipatch进行信息查询,
如组成Multipatch的几何图形信息,个数,类型等等

这两天研究了Multipatch,自己创建了一个简单的3D模型在ArSence下,对Multipatch有了新的认识,整理一下学习笔记,希望和大家一起学习.
说明如下:
目的:创建一个简单Multipatch对象模型。
开发环境:ArSence下的VBA
实现效果:一个3D房子模型。
代码如下所示:
1。  ''VBA下的按钮实现函数
''当按钮点击事件发生时将调用  GetMultipatch函数,以便创建三维模型
Private Sub UIButtonControl1_Click()    
    Call GetMultipatch           
End Sub
2。GetMultipatch函数实现过程
''这个函数中首先需要创建3D符号,所以需要调用IMarker3DSymbol接口实现
''然后将创建好的IMarker3DSymbol符号作为一个Element元素添加到Sence的地图窗口中
Public Sub GetMultipatch()
  ''创建新的3D符号
  Dim pMarker3DSymbol As IMarker3DSymbol: Set pMarker3DSymbol = New Marker3DSymbol
  Set pMarker3DSymbol.Shape = GetGeometry()        ''设置3D符号几何形体(Multipatch)

  ''AppRef为当前正在运行的应用程序
  ''需要注意的是,本实例所创建的3DMultipatch是一个点的3DSymbol,所以使用Point创建
  Dim pSxApp As IApplication: Set pSxApp = New AppRef    ''获取当前地图应用程序Application
  Dim pPt As IPoint: Set pPt = New Point: pPt.X = 0#: pPt.Y = 0#: pPt.Z = 0#
  AddGraphic pSxApp, pPt, pMarker3DSymbol, , False    ''设定坐标原点,并加入Element对象元素
 
End Sub
3。''创建3D符号填充的几何形体,使用  GetGeometry函数实现,具体如下所示;
Function GetGeometry() As IGeometry
''创建Multipatch的点对象
    ''创建第一个Part中的点对象(东面的墙)
    Dim pT1 As IPoint, pT2 As IPoint, pT3 As IPoint, pT4 As IPoint
    Set pT1 = New Point
    pT1.X = 10: pT1.Y = 0:  pT1.Z = 0
    Set pT2 = New Point
    pT2.X = 10: pT2.Y = 0:  pT2.Z = 3
    Set pT3 = New Point
    pT3.X = 10: pT3.Y = 6:  pT3.Z = 3
    Set pT4 = New Point
    pT4.X = 10: pT4.Y = 6: pT4.Z = 0
    ''创建第二个Part中的点对象(北面的墙)
    Dim ppt1 As IPoint, ppt2 As IPoint
    Set ppt1 = New Point
    ppt1.X = 0: ppt1.Y = 6: ppt1.Z = 0
    Set ppt2 = New Point
    ppt2.X = 0: ppt2.Y = 6: ppt2.Z = 3
    ''创建第三个Part中的点对象(西面的墙)
    Dim ppt3 As IPoint, ppt4 As IPoint
    Set ppt3 = New Point
    ppt3.X = 0: ppt3.Y = 0: ppt3.Z = 3
    Set ppt4 = New Point
    ppt4.X = 0: ppt4.Y = 0: ppt4.Z = 0
    ''创建第四个Part中的点对象(南面的墙)
    ''其中南面的墙也是正面的,设计了一个门和一个窗户
    ''所以第四部分是由外环和内环组成的(本例子中窗子作为了内环处理的)
    ''下面是创建外环的点对象
    Dim inpt1 As IPoint, inpt2 As IPoint, inpt3 As IPoint, inpt4 As IPoint
    Set inpt1 = New Point
    Set inpt2 = New Point
    Set inpt3 = New Point
    Set inpt4 = New Point
    ''创建门组成的点
    inpt1.X = 2: inpt1.Y = 0: inpt1.Z = 0
    inpt2.X = 2: inpt2.Y = 0: inpt2.Z = 2
    inpt3.X = 4: inpt3.Y = 0: inpt3.Z = 2
    inpt4.X = 4: inpt4.Y = 0: inpt4.Z = 0
    ''创建第五部分 内环窗子的组成点对象
    Dim interpt1 As IPoint, interpt2 As IPoint, interpt3 As IPoint, interpt4 As IPoint
    Set interpt1 = New Point
    Set interpt2 = New Point
    Set interpt3 = New Point
    Set interpt4 = New Point
    interpt1.X = 6: interpt1.Y = 0: interpt1.Z = 1
    interpt2.X = 6: interpt2.Y = 0: interpt2.Z = 2
    interpt3.X = 8: interpt3.Y = 0: interpt3.Z = 2
    interpt4.X = 8: interpt4.Y = 0: interpt4.Z = 1
    ''创建第六、七、八、九部分 构建房顶 三角形 的点对象
    Dim pRoofTop As IPoint
    Dim pRoofD1 As IPoint, pRoofD2 As IPoint, pRoofD3 As IPoint, pRoofD4 As IPoint

    Set pRoofTop = New Point: Set pRoofD2 = New Point
    Set pRoofD1 = New Point: Set pRoofD3 = New Point: Set pRoofD4 = New Point
    pRoofTop.X = 5: pRoofTop.Y = 3: pRoofTop.Z = 5
    pRoofD1.X = 10: pRoofD1.Y = 0: pRoofD1.Z = 3
    pRoofD2.X = 10: pRoofD2.Y = 6: pRoofD2.Z = 3
    pRoofD3.X = 0: pRoofD3.Y = 6: pRoofD3.Z = 3
    pRoofD4.X = 0: pRoofD4.Y = 0: pRoofD4.Z = 3
    ''以下的点对象是用来创建 纹理贴图使用的,表示纹理图片的贴图的位置
    Dim s As Integer, t As Integer
    s = 1: t = 10
    Dim pTxLL0 As IPoint, pTxLR0 As IPoint, pTxUR0 As IPoint, pTxUL0 As IPoint
    Set pTxLL0 = New Point: Set pTxLR0 = New Point: Set pTxUR0 = New Point:: Set pTxUL0 = New Point
    pTxUL0.X = 6#: pTxUL0.Y = 0#: pTxUR0.X = s: pTxUR0.Y = 0#
    pTxLL0.X = 6#: pTxLL0.Y = t: pTxLR0.X = s: pTxLR0.Y = t
   
    ''创建Multipatch几何形体对象
    ''使用pGenralMultipatch对象进行初始化所要创建的几何对象要素
    ''首先需要使用Init方法来初始化Multipatch,使用IGeneralMultiPatchCreator接口
    Dim pGenralMultipatch As IGeneralMultiPatchCreator
    Set pGenralMultipatch = New GeneralMultiPatchCreator
    ''本实例中Init方法有以下几个参数,解释如下:
    ''41表示Multipatch所包含的点的个数,本实例所创建的房子对象需要41个点对象。包括重复的点对象,如两个面的相交面 公用的点也需要重新计算近来
    ''9表示Multipatch对象包含的部分数量,本实例中包含东、西、南、北、前面前的内环窗子部分、以及四个屋顶的三角扇形部分,共9个
    ''参数中的3个False可以采用默认的方式
    ''39表示的是纹理贴图所用的点数,一般情况下是与Multipatch所包含点个数是相同的;这个数量可以控制纹理贴图效果;
    ''GetMateriallist函数是添加纹理图像的函数,本例子中共添加了7个bmp格式的影像
    pGenralMultipatch.Init 41, 9, False, False, True, 39, GetMaterialList
   
    Dim dictWalls As Scripting.Dictionary: Set dictWalls = GetWall
    ''创建第一个部分,其中 第一个0表示创建的部分,第二个0表示贴纹理所使用的纹理序号,第3,4个表示纹理贴图的点号
    ''其中PartSetUp表示创建Multipatch的part设置
    ''说明如下:pGenralMultipatch为当前的Multipatch对象
    ''esriPatchTypeRing表示所创建的类型
    ''第一个0表示创建的部分序号
    ''第二个0表示纹理序号
    ''第3,4个表示纹理点对象序号
    PartSetUp pGenralMultipatch, 0, esriPatchTypeRing, 0, 0, 0
    ''表示对当前部分进行点对象的设置
    ''参数说明如下:pGenralMultipatch为当前的Multipatch对象
    ''第一个数字参数表示当前这个部分所包含的点的序号,第二个参数表示当前部分所包含的点
    ''第三个参数表示纹理贴图所包含的点
    PointSetUp pGenralMultipatch, 0, pT1, pTxLL0
    PointSetUp pGenralMultipatch, 1, pT2, pTxLR0
    PointSetUp pGenralMultipatch, 2, pT3, pTxUR0
    PointSetUp pGenralMultipatch, 3, pT4, pTxUL0
    PointSetUp pGenralMultipatch, 4, pT1, pTxLL0
    ''创建第2个部分
    PartSetUp pGenralMultipatch, 1, esriPatchTypeRing, 1, 5, 5
    PointSetUp pGenralMultipatch, 5, pT3, pTxLL0
    PointSetUp pGenralMultipatch, 6, pT4, pTxLR0
    PointSetUp pGenralMultipatch, 7, ppt1, pTxUR0
    PointSetUp pGenralMultipatch, 8, ppt2, pTxUL0
    PointSetUp pGenralMultipatch, 9, pT3, pTxLL0
    Set GetGeometry = pGenralMultipatch.CreateMultiPatch
    ''创建第3个部分
    PartSetUp pGenralMultipatch, 2, esriPatchTypeRing, 2, 10, 10
   
    PointSetUp pGenralMultipatch, 10, ppt1, pTxLL0
    PointSetUp pGenralMultipatch, 11, ppt2, pTxLR0
    PointSetUp pGenralMultipatch, 12, ppt3, pTxUR0
    PointSetUp pGenralMultipatch, 13, ppt4, pTxUL0
    PointSetUp pGenralMultipatch, 14, ppt1, pTxLL0
    Set GetGeometry = pGenralMultipatch.CreateMultiPatch
    ''4个部分
    PartSetUp pGenralMultipatch, 3, esriPatchTypeOuterRing, 3, 15, 15
    PointSetUp pGenralMultipatch, 15, ppt3, pTxLL0
    PointSetUp pGenralMultipatch, 16, ppt4, pTxLR0
    PointSetUp pGenralMultipatch, 17, inpt1, pTxUR0
    PointSetUp pGenralMultipatch, 18, inpt2, pTxUL0
    PointSetUp pGenralMultipatch, 19, inpt3, pTxLL0
    PointSetUp pGenralMultipatch, 20, inpt4, inpt4
    PointSetUp pGenralMultipatch, 21, pT1, pT1
    PointSetUp pGenralMultipatch, 22, pT2, pT2
    PointSetUp pGenralMultipatch, 23, ppt3, ppt3
    Set GetGeometry = pGenralMultipatch.CreateMultiPatch
    ''5个部分
    PartSetUp pGenralMultipatch, 4, esriPatchTypeInnerRing, -1, 24, 24
    PointSetUp pGenralMultipatch, 24, interpt1, interpt1
    PointSetUp pGenralMultipatch, 25, interpt2, interpt2
    PointSetUp pGenralMultipatch, 26, interpt3, interpt3
    PointSetUp pGenralMultipatch, 27, interpt4, interpt4
    PointSetUp pGenralMultipatch, 28, interpt1, interpt1
    ''第6个部分
    PartSetUp pGenralMultipatch, 5, esriPatchTypeTriangles, 5, 29, 29
    PointSetUp pGenralMultipatch, 29, pRoofTop, pRoofTop
    PointSetUp pGenralMultipatch, 30, pRoofD1, pRoofD1
    PointSetUp pGenralMultipatch, 31, pRoofD2, pRoofD2
    ''第7个部分
    PartSetUp pGenralMultipatch, 6, esriPatchTypeTriangles, 4, 32, 32
    PointSetUp pGenralMultipatch, 32, pRoofTop, pRoofTop
    PointSetUp pGenralMultipatch, 33, pRoofD2, pRoofD2
    PointSetUp pGenralMultipatch, 34, pRoofD3, pRoofD3
    ''第8个部分

 

PartSetUp pGenralMultipatch, 7, esriPatchTypeTriangles, 5, 35, 35
    PointSetUp pGenralMultipatch, 35, pRoofTop, pRoofTop
    PointSetUp pGenralMultipatch, 36, pRoofD3, pRoofD3
    PointSetUp pGenralMultipatch, 37, pRoofD4, pRoofD4
    ''第9个部分
    PartSetUp pGenralMultipatch, 8, esriPatchTypeTriangles, 0, 38, 38
    PointSetUp pGenralMultipatch, 38, pRoofTop, pRoofTop
    PointSetUp pGenralMultipatch, 39, pRoofD4, pRoofD4
    PointSetUp pGenralMultipatch, 40, pRoofD1, pRoofD1
    ''创建Multipatch对象
    Set GetGeometry = pGenralMultipatch.CreateMultiPatch
End Function
4。''向IGeometryMaterial中添加纹理图片
''以后以便向part中添加这个图片纹理
'The texture images are saved in a sub-folder called TextureFolder under the ArcScene document:
Function GetMaterialList() As IGeometryMaterialList
On Error GoTo eh

  'create new materials:
  ''纹理存放的路径
  Dim sTexFolder As String: sTexFolder = "D:\ArcGIS\DeveloperKit\SamplesCOM\3D_Analyst\TexturedMultipatchVisual_Basic\TexturedMultipatchVisual_Basic\Visual_Basic\TextureFolder\"

  'material 1:
  Dim pMaterial1 As IGeometryMaterial: Set pMaterial1 = New GeometryMaterial
  pMaterial1.TextureImage = sTexFolder & "tile_roo.jpg"   'the mission tile

'  material 2:
  Dim pMaterial2 As IGeometryMaterial: Set pMaterial2 = New GeometryMaterial
  pMaterial2.TextureImage = sTexFolder & "block2.jpg"

'  material 3:
  Dim pMaterial3 As IGeometryMaterial: Set pMaterial3 = New GeometryMaterial
  pMaterial3.TextureImage = sTexFolder & "brick1.jpg"

  'material 4:
  Dim pMaterial4 As IGeometryMaterial: Set pMaterial4 = New GeometryMaterial
  pMaterial4.TextureImage = sTexFolder & "concrete1.jpg"

  'material 5:
  Dim pMaterial5 As IGeometryMaterial: Set pMaterial5 = New GeometryMaterial
  pMaterial5.TextureImage = sTexFolder & "stucco3.jpg"

  'material 6:
  Dim pMaterial6 As IGeometryMaterial: Set pMaterial6 = New GeometryMaterial
  'pMaterial6.TextureImage = sTexFolder & "dessau.jpg"
  pMaterial6.TextureImage = sTexFolder & "worlitz.jpg"
  
  'create a new material list and add the material to the material list:
  Set GetMaterialList = New GeometryMaterialList
  GetMaterialList.AddMaterial pMaterial1
  GetMaterialList.AddMaterial pMaterial2
  GetMaterialList.AddMaterial pMaterial3
  GetMaterialList.AddMaterial pMaterial4
  GetMaterialList.AddMaterial pMaterial5
  GetMaterialList.AddMaterial pMaterial6
End Function
5,第五部分
''设置Part每个部分的属性信息
''具体参数如下PartSetUp函数所示:
''pCreator为创建Multipatch的对象,partIndex表示部分part的索引号,parttype表示part部分的类型信息,materialindex表示texture(纹理)的索引号
''partPointIndex表示当前所要设置part的点的组成,partTexturePointIndex表示当前part的纹理贴图所用的点的索引号
Public Sub PartSetUp(ByRef pCreator As IGeneralMultiPatchCreator, _
          partIndex As Integer, partType As esriPatchType, materialIndex As Integer, _
          partPointIndex As Integer, Optional partTexturePointIndex As Integer)
  With pCreator
    .SetPatchType partIndex, partType
    .SetMaterialIndex partIndex, materialIndex
    .SetPatchPointIndex partIndex, partPointIndex
    If Not IsMissing(partTexturePointIndex) Then
      .SetPatchTexturePointIndex partIndex, partTexturePointIndex
    End If
  End With
End Sub
6,第六部分
'‘设置点的属性信息:
''参数如下所示:
''pCreator表示当前创建MultiPatch的对象,pointIndex表示点的索引号
Public Sub PointSetUp(ByRef pCreator As IGeneralMultiPatchCreator, _
              pointIndex As Integer, pPtZ As IPoint, Optional pTexPt As IPoint = Nothing)
  pCreator.SetPoint pointIndex, pPtZ
  If Not pTexPt Is Nothing Then pCreator.SetTexturePoint pointIndex, pTexPt
End Sub
7,第七部分
''添加Multipatch 为element,并显示在sence上
Public Sub AddGraphic(pApp As IApplication, _
  pGeom As IGeometry, _
  Optional pSym As ISymbol, _
  Optional bAddToSelection As Boolean = False, _
  Optional bSelect As Boolean = True, _
  Optional sElementName As String) ' TODO this needs to change

  On Error GoTo AddGraphic_ERR

  If pGeom.IsEmpty Then Exit Sub

  Dim pElement As IElement

  Select Case pGeom.GeometryType
    Case esriGeometryPoint
      Set pElement = New MarkerElement
      Dim pPointElement As IMarkerElement: Set pPointElement = pElement
      If Not pSym Is Nothing Then pPointElement.Symbol = pSym
    Case esriGeometryPolyline
      Set pElement = New LineElement
      Dim pLineElement As ILineElement: Set pLineElement = pElement
      If Not pSym Is Nothing Then pLineElement.Symbol = pSym
    Case esriGeometryPolygon
      Set pElement = New PolygonElement
      Dim pFillElement As IFillShapeElement: Set pFillElement = pElement
      If Not pSym Is Nothing Then pFillElement.Symbol = pSym
    Case esriGeometryMultiPatch
      Set pElement = New MultiPatchElement
      Set pFillElement = pElement
      If Not pSym Is Nothing Then pFillElement.Symbol = pSym
  End Select

  pElement.Geometry = pGeom
  If Len(sElementName) > 0 Then
    Dim pElemProps As IElementProperties: Set pElemProps = pElement
    pElemProps.Name = sElementName
  End If

  Dim pGLayer As IGraphicsLayer
  If (TypeOf pApp Is IMxApplication) Then
    Dim pMxDoc As IMxDocument: Set pMxDoc = pApp.Document
    Dim pActiveView As IActiveView: Set pActiveView = pMxDoc.FocusMap
    Set pGLayer = pMxDoc.FocusMap.BasicGraphicsLayer
    Dim pGCon As IGraphicsContainer: Set pGCon = pGLayer

    pGCon.AddElement pElement, 0

    Dim pGCS As IGraphicsContainerSelect
    Set pGCS = pGCon
    ' unselect all other elements before selecting this one:
    If Not bAddToSelection Then pGCS.UnselectAllElements
    pGCS.SelectElement pElement

    ' redraw graphics for entire view extent, rather than just extent of this element, in case there were
    ' other graphics present that became unselected and lost their selection handles
    pActiveView.PartialRefresh esriViewGraphics, pElement, pActiveView.Extent
  Else
    Dim pSxDoc As ISxDocument: Set pSxDoc = pApp.Document
    Set pGLayer = pSxDoc.Scene.BasicGraphicsLayer
    'set lighting to true:
    Dim pLyrExt As ILayerExtensions: Set pLyrExt = pGLayer
    Dim p3DProp As I3DProperties: Set p3DProp = pLyrExt.Extension(0)
    p3DProp.Illuminate = False
    Dim pGCon3D As IGraphicsContainer3D: Set pGCon3D = pGLayer

    pGCon3D.DeleteAllElements
    pGCon3D.AddElement pElement

    Dim pGS As IGraphicsSelection: Set pGS = pGCon3D
    If (bSelect) Then
      ' unselect all other elements before selecting this one
      If Not bAddToSelection Then pGS.UnselectAllElements
      pGS.SelectElement pElement
    End If

    pSxDoc.Scene.SceneGraph.RefreshViewers
  End If

  Exit Sub
AddGraphic_ERR:
  Debug.Print "AddGraphic_ERR: " & Err.Description
  Debug.Assert 0
End Sub

''注意事项:
''Multipatch其实是表示多个几何要素所组成的格外一个几何对象,大多情况下是带有高程值的
''在上述的例子中,一个Multipatch所表示的就是由四个矩形和4个三角形所组成的
''当我们想为一个不带有高程信息的一个平面对象赋予一定的纹理的时候,一定要设置组成平面的点的Z值;Z=0才能显示出来;
''同时,还需要注意pGenralMultipatch.Init 41, 9, False, False, True, 39, GetMaterialList这条语句,里面的数字参数设置会改变一定的显示效果,需要注意;
''还有就是要 注意PartSetUp pGenralMultipatch, 4, esriPatchTypeInnerRing, -1, 24, 24
                 PointSetUp pGenralMultipatch, 24, interpt1, interpt1
''设置part与point的函数参数

 

使用方法:打开ARcscene,打开tool-macros-visualbasic Editer

ProjectArcSceneObjectsThisDocument上双击,然后将下列代码贴入:运行之后便会形成房屋形状。

 

posted on 2009-04-17 10:41  大胡子青松  阅读(1692)  评论(0编辑  收藏  举报

导航