0% found this document useful (0 votes)
137 views162 pages

3DDOTNETGuide

Uploaded by

Yantao Wu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
137 views162 pages

3DDOTNETGuide

Uploaded by

Yantao Wu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 162

Intergraph Smart™ 3D .

NET
Programmer’s Guide

Version 2016 April 2016 DSP3D-PE-200080F


Copyright
Copyright © 2009-2016 Intergraph Corporation ®. All Rights Reserved. Intergraph is part of Hexagon.
Including software, file formats, and audiovisual displays; may be used pursuant to applicable software license
agreement; contains confidential and proprietary information of Intergraph and/or third parties which is protected by
copyright law, trade secret law, and international treaty, and may not be provided or otherwise made available
without proper authorization from Intergraph Corporation.
Portions of the user interface copyright 2012-2013 Telerik AD.
U.S. Government Restricted Rights Legend
Use, duplication, or disclosure by the Government is subject to restrictions as set forth in subparagraph (c) of the
Contractor Rights in Technical Data clause at DFARS 252.227-7013, subparagraph (b) of the Rights in Computer
Software or Computer Software Documentation clause at DFARS 252.227-7014, subparagraphs (b)(1) and (2) of the
License clause at DFARS 252.227-7015, or subparagraphs (c) (1) and (2) of Commercial Computer Software---
Restricted Rights at 48 CFR 52.227-19, as applicable.
Unpublished---rights reserved under the copyright laws of the United States.
Intergraph Corporation
300 Intergraph Way
Huntsville, Alabama 35813
Documentation
Documentation shall mean, whether in electronic or printed form, User’s Guides, Installation Guides, Reference
Guides, Administrator’s Guides, Customization Guides, Programmer’s Guides, Configuration Guides and Help
Guides delivered with a particular software product.
Other Documentation
Other Documentation shall mean, whether in electronic or printed form and delivered with software or on
eCustomer, SharePoint, or box.net, and documentation related to work processes, workflows, and best practices that
is provided by Intergraph as guidance for using a software product.
Terms of Use
a. Use of software product and Documentation is subject to the End User License Agreement (EULA) delivered
with software product unless the Licensee has a valid signed license for this software product with Intergraph
Corporation. If the Licensee has a valid signed license for this software product with Intergraph Corporation,
the valid signed license shall take precedence and govern the use of this software product and Documentation.
Subject to the terms contained within the applicable license agreement, Intergraph Corporation gives Licensee
permission to print a reasonable number of copies of the Documentation as defined in the applicable license
agreement and delivered with the software product for Licensee’s internal, non-commercial use. The
Documentation may not be printed for resale or redistribution.
b. For use of Documentation or Other Documentation where end user does not receive a EULA or does not have a
valid license agreement with Intergraph, Intergraph grants the Licensee a non-exclusive license to use the
Documentation or Other Documentation for Licensee’s internal non-commercial use. Intergraph Corporation
gives Licensee permission to print a reasonable number of copies of Other Documentation for Licensee’s
internal, non-commercial use. The Other Documentation may not be printed for resale or redistribution. This
license contained in this subsection b) may be terminated at any time and for any reason by Intergraph
Corporation by giving written notice to Licensee.
Disclaimer of Warranties
Except for any express warranties as may be stated in the EULA or separate license or separate terms and
conditions, Intergraph Corporation disclaims any and all express or implied warranties including, but not limited to
the implied warranties of merchantability and fitness for a particular purpose and nothing stated in, or implied by,
this document or its contents shall be considered or deemed a modification or amendment of such disclaimer.
Intergraph believes the information in this publication is accurate as of its publication date.
The information and the software discussed in this document are subject to change without notice and are subject to
applicable technical product descriptions. Intergraph Corporation is not responsible for any error that may appear in
this document.
The software, Documentation and Other Documentation discussed in this document are furnished under a license
and may be used or copied only in accordance with the terms of this license. THE USER OF THE SOFTWARE IS
EXPECTED TO MAKE THE FINAL EVALUATION AS TO THE USEFULNESS OF THE SOFTWARE IN HIS
OWN ENVIRONMENT.
Intergraph is not responsible for the accuracy of delivered data including, but not limited to, catalog, reference and
symbol data. Users should verify for themselves that the data is accurate and suitable for their project work.
Limitation of Damages
IN NO EVENT WILL INTERGRAPH CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT,
CONSEQUENTIAL INCIDENTAL, SPECIAL, OR PUNITIVE DAMAGES, INCLUDING BUT NOT LIMITED
TO, LOSS OF USE OR PRODUCTION, LOSS OF REVENUE OR PROFIT, LOSS OF DATA, OR CLAIMS OF
THIRD PARTIES, EVEN IF INTERGRAPH CORPORATION HAS BEEN ADVISED OF THE POSSIBILITY
OF SUCH DAMAGES.
UNDER NO CIRCUMSTANCES SHALL INTERGRAPH CORPORATION'S LIABILITY EXCEED THE
AMOUNT THAT INTERGRAPH CORPORATION HAS BEEN PAID BY LICENSEE UNDER THIS
AGREEMENT AT THE TIME THE CLAIM IS MADE. EXCEPT WHERE PROHIBITED BY APPLICABLE
LAW, NO CLAIM, REGARDLESS OF FORM, ARISING OUT OF OR IN CONNECTION WITH THE
SUBJECT MATTER OF THIS DOCUMENT MAY BE BROUGHT BY LICENSEE MORE THAN TWO (2)
YEARS AFTER THE EVENT GIVING RISE TO THE CAUSE OF ACTION HAS OCCURRED.
IF UNDER THE LAW RULED APPLICABLE ANY PART OF THIS SECTION IS INVALID, THEN
INTERGRAPH LIMITS ITS LIABILITY TO THE MAXIMUM EXTENT ALLOWED BY SAID LAW.
Export Controls
Intergraph Corporation's software products and any third-party Software Products obtained from Intergraph
Corporation, its subsidiaries, or distributors (including any Documentation, Other Documentation or technical data
related to these products) are subject to the export control laws and regulations of the United States. Diversion
contrary to U.S. law is prohibited. These Software Products, and the direct product thereof, must not be exported or
re-exported, directly or indirectly (including via remote access) under the following circumstances:
a. To Cuba, Iran, North Korea, Sudan, or Syria, or any national of these countries.
b. To any person or entity listed on any U.S. government denial list, including but not limited to, the U.S.
Department of Commerce Denied Persons, Entities, and Unverified lists, the U.S. Department of Treasury
Specially Designated Nationals List, and the U.S. Department of State Debarred List.
c. To any entity when Licensee knows, or has reason to know, the end use of the Software Product is related to the
design, development, production, or use of missiles, chemical, biological, or nuclear weapons, or other un-
safeguarded or sensitive nuclear uses.
d. To any entity when Licensee knows, or has reason to know, that an illegal reshipment will take place.
Any questions regarding export or re-export of these Software Products should be addressed to Intergraph
Corporation's Export Compliance Department, Huntsville, Alabama 35894, USA.
Trademarks
Intergraph, the Intergraph logo, Intergraph Smart, PDS, SmartPlant, SmartMarine, FrameWorks, I-Sketch,
IntelliShip, ISOGEN, SmartSketch, SPOOLGEN, Sapphire, SupportManager, and SupportModeler are trademarks
or registered trademarks of Intergraph Corporation or its subsidiaries in the United States and other countries.
Microsoft and Windows are registered trademarks of Microsoft Corporation. MicroStation is a registered trademark
of Bentley Systems, Inc. Other brands and product names are trademarks of their respective owners.
Intergraph Policy Against Software Piracy
When you purchase or lease Intergraph software, Intergraph retains ownership of the product. You become the
licensee of the product and obtain the right to use the product solely in accordance with the terms of the Intergraph
Software License Agreement and the provisions of the various copyright laws.
You must have a valid license for each working copy of the product. You may also make one archival copy of the
software to protect from inadvertent destruction of the original software, but you are not permitted to use the
archival copy for any other purpose. An upgrade replaces the original license. Any use of working copies of the
product for which there is no valid Intergraph Software License Agreement constitutes Software Piracy for which
there are very severe penalties. All Intergraph software products are protected by copyright laws and international
treaty.
If you have questions regarding software piracy or the legal use of Intergraph software products, please call the
Intergraph Legal Department at 256-730-2333.
Updated July, 2003. Document No. DDGL562B0
Table of Contents

Table of Contents
Preface .................................................................................................................................6
Documentation Comments ...........................................................................................6

Introduction ........................................................................................................................7

Getting Started ...................................................................................................................8


What’s New for Smart 3D .NET API ...........................................................................8
Intended Audience ........................................................................................................8
Resources and References ..........................................................................................10
Using the Visual Studio 2013 Microsoft Help Viewer ...............................................11
Managing Visual Studio Integrated Documentation ......................................................... 11

3D Three-Tier Architecture ............................................................................................15


Client Tier ...................................................................................................................16
Middle (Business) Tier ...............................................................................................17
Server Tier ..................................................................................................................18

Architecture in Smart 3D .NET ......................................................................................19


Interfaces and Class Implementation ..........................................................................20
Polymorphism .............................................................................................................21

Namespaces and Assemblies ...........................................................................................22


Namespaces ................................................................................................................23
Assemblies ..................................................................................................................24

Creating Commands ........................................................................................................25


Types of Commands ...................................................................................................26
Command Assistants ..................................................................................................30
Creating a Command Solution and Project ................................................................31
Writing Commands: Modal Command ......................................................................36
Writing Commands: Graphic Command ....................................................................42
Writing Commands: Step Command ..........................................................................46
Important Changes for CommonMiddle and CommonClient ....................................53

Creating Naming Rules ...................................................................................................54


Base class - NameRuleBase........................................................................................55
Creating a NameRule Project .....................................................................................57
Writing a Name Rule ..................................................................................................59
Deployment.................................................................................................................64

Programming a Stand-Alone Application .....................................................................66

Intergraph Smart™ 3D .NET Programmer’s Guide 3


Table of Contents

Introduction ....................................................................................................................... 66
Available Tools ................................................................................................................. 66
Writing the Stand-Alone Application ............................................................................... 67
SAPBase Example Projects .............................................................................................. 70
Runtime and Build Considerations ................................................................................... 70

Localization ......................................................................................................................73
Introduction ....................................................................................................................... 73
Adding a Resource File..................................................................................................... 73
Creating Batch File to Build Resource DLL..................................................................... 75
Adding Resource Identifier Class ..................................................................................... 77
Adding Localizer Class ..................................................................................................... 77

Custom Folders for User Assemblies .............................................................................79

Security Issues when Deploying Assemblies on a Shared Network ............................80


.NET Framework 4.0 ........................................................................................................ 80
.NET Framework 4.5.2 ..................................................................................................... 80

Creating .NET Symbols ...................................................................................................82


Understanding the Geometry ......................................................................................83
Defining Ports on Symbols ............................................................................................... 84
Writing Code for the .NET Symbol ............................................................................85
Assembly Creation ............................................................................................................ 85
Deploying the Symbols ..................................................................................................... 85
Naming of the Symbol Definition..................................................................................... 85
Creating Custom To Do List Messages ............................................................................ 86
Bulkloading the Symbol .............................................................................................88
Bulkloading the Piping Symbol ........................................................................................ 88
Placing the Symbol .....................................................................................................89
Creating an Advanced Symbol ...................................................................................90
Dynamic Outputs .............................................................................................................. 90
Custom Weight and Center of Gravity (COG) ................................................................. 90
Custom Evaluation of Origin and Orientation .................................................................. 91
Custom Foul Check........................................................................................................... 92
Custom Mirror .................................................................................................................. 93
Custom Property Management ......................................................................................... 94
Creating .NET symbols using the Symbol Wizard ........................................................... 96
Application-specific Symbol Definition Base Classes ..................................................... 96
Migrating an Existing Symbol to .NET ......................................................................97
Using the Symbol Wizard for Migration .......................................................................... 97
Creating a Custom Assembly .....................................................................................98
Defining a Custom Assembly ........................................................................................... 98
Defining Assembly Outputs .............................................................................................. 98
Creating and Evaluating Assembly Outputs ..................................................................... 98
Allowing End Users to Delete Assembly Outputs .......................................................... 100
Dynamic Outputs ............................................................................................................ 100
Bulkloading a Custom Assembly.................................................................................... 101

4 Intergraph Smart™ 3D .NET Programmer’s Guide


Table of Contents

Creating Batch Commands for Project Management ................................................103


Job Submission ............................................................................................................... 103
Job Execution .................................................................................................................. 105
Configuring Queues for a Custom Batch Job ...........................................................107

Reference Data Calculation Rules ................................................................................108


Custom Wall Thickness and Branch Reinforcement Calculation ............................109
Creating a .NET Project for a New Rule ........................................................................ 109
Calculation Logic ProgIDs for Worksheets .................................................................... 111
Calculation Logic for the Wall Thickness Calculation.............................................113
Calculation Logic for the Branch Reinforcement Calculation .................................120
GetBranchReinforcementPadData Method..................................................................... 120
GetBranchReinforcementWeldData Method .................................................................. 141

Appendix A: Usage Caveats ..........................................................................................158


SP3DConnection.DatabaseID Works Only for the Active Connection ...................159

Index ................................................................................................................................160

Intergraph Smart™ 3D .NET Programmer’s Guide 5


Preface

Preface
This document is a user's guide for programming and customization using the Smart 3D .NET
programming layer and provides information about creating custom commands, naming rules,
and stand-alone applications with this new technology.

Documentation Comments
Send documentation comments or suggestions to PPMdoc@intergraph.com.

6 Intergraph Smart™ 3D .NET Programmer’s Guide


Introduction

Introduction
The Intergraph Smart™ 3D .NET Programmer's Guide provides introductory information to
developers who want to create custom commands or custom programs using special tools and the
software. Before creating commands or programs, you must be very familiar with the software
interactively and understand its basic concepts of projects, engineering, architecture,
concurrency, and datastores.
For more specific information about creating commands using the software application
programming interface (API), please contact Intergraph Services.
This programming guide includes:
• An overview of customization with the software using Microsoft Visual Studio™.
• Some of the user-definable methods of implementation, such as creating commands
and naming rules.
• Examples and workflows.
The 3D .NET object model provides an easy-to-use .NET programming layer for external
customers and internal-use.
• Provides developers a comprehensible way to filter and locate objects and commit
changes to the database.
• Communicates with the existing middle tier 3D business objects and semantics so that all
modifications made to the plant and marine model remain consistent and valid.
• Consists of a set of common objects working with database connections, transactions,
filters, and so forth, including a set of objects and constructs in the application layer.
The 3D .NET object model is built as a set of .NET objects which wrap COM objects. A primary
issue in using .NET to manipulate the 3D business objects is communicating between .NET and
COM. The 3D COM business objects only come into existence as transactions are made against
the underlying database. When a transaction is committed or aborted, business objects essentially
disappear. Only their monikers remain.
The 3D .NET object model provides a base class called BusinessObject, which generically
wraps 3D business objects. BusinessObject provides a way to access and modify properties
using a dictionary approach. Applications extend the object model by subclassing from this base
class.

Intergraph Smart™ 3D .NET Programmer’s Guide 7


Getting Started

Getting Started
Before you begin using the 3D .NET programming layer, you should be familiar with the
following:
• Microsoft Visual Studio .NET technology
• Understanding of object-oriented programming principles
• Basic understanding of the 3D data model and functionality
• Understanding traversal of the 3D Schema Browser
• Basic understanding of relational databases

What’s New for Smart 3D .NET API


• Visual Studio 2013 is the only valid version of development software for this release
of the Smart 3D .NET API.
• A new base class has been defined for equipment components. If you have existing
equipment component symbols, it is recommended that you modify your code to
inherit from EquipmentComponentAssemblyDefinition class.
• Only new rules should be added to an existing catalog. For more information, see
Deployment section of Creating Naming Rules.
• Changes with CommonApp functionality require users to recompile existing projects
– for more information, see Important Changes for CommonMiddle and
CommonClient section of Creating Commands.
• Changes with PrjMgmtMiddle functionality for batch processing. Batch Services has
been moved from the Client Services tier to the Middle tier of the PrjMgmtMiddle
project. For more information, see Creating Batch Commands for Project
Management.
• Changes with ReferenceDataMiddle and new RefdataRuleBase by providing
calculation rule information for wall thickness and branch reinforcement calculation.
See Reference Data Calculation Rules section for more information and a custom
wall thickness and branch reinforcement calculation project sample.
• Now provide support for writing .NET callbacks to customize processing for
integration workflows. For more information, see EFAdapterCallbackRule and its
enumerators in the CommonMiddle .NET API services functionality.

Intended Audience
• Those who want to customize within the framework of S3DHost – writing
commands, name rules, and creating symbols.
• Those who want to write applications to access the middle tier – to execute as a stand-
alone application independent of S3DHost.
• Those who want to develop new functionality using .NET at the client-level with
commands, GUI, and services.

8 Intergraph Smart™ 3D .NET Programmer’s Guide


Getting Started

• 3rd party developers who want to extend 3D functionality.

Intergraph Smart™ 3D .NET Programmer’s Guide 9


Getting Started

Resources and References


The best source for programming reference information is contained in the documentation and
Help provided with your programming tool whether online or installed locally. Microsoft Visual
Studio provides helpful programming information online and integrated with the software and
displayable locally with the Microsoft Help Viewer. If you have installed Microsoft
documentation on your machine, you can display this information by first selecting Help > Set
Help Preference > Launch in Help Viewer. Then, select Help > View Help or with Visual
Studio as the “active” application, press F1.
Microsoft provides the ability to integrate other documentation, such as Intergraph’s
programming documentation, within the Visual Studio environment. You can view Intergraph’s
.NET programming information directly in versions of Visual Studio 2010 and later by selecting
Help > View Help.
Microsoft installed documentation includes:
• Detailed Visual Studio information
• Microsoft Help System Documentation

10 Intergraph Smart™ 3D .NET Programmer’s Guide


Getting Started

Using the Visual Studio 2013 Microsoft Help


Viewer
To implement and activate the Visual Studio help system, establish display connectivity with the
Microsoft Help Viewer, installed by default for Visual Studio 2013 in the C:\Program Files
(x86)\Microsoft Help Viewer\v2.1 folder.
Microsoft refers to completing this connectivity as setting the local help store content.

First Time Use of Visual Studio 2013 Help System


1. Open Visual Studio and click Help to display:

2. Select Set Help Preference > Launch in Help Viewer.

Managing Visual Studio Integrated Documentation


When you want to display installed and registered documentation on your computer, click Help
> View Help. This launches the Microsoft Help Viewer. If your API documentation of interest
is already displayed in the Contents section, then it is ready for review. If not, you must add the
help content by installing the product manifest.

Adding Help Content by Installing the Product Manifest


Only two files for each individual.NET API project are required to provide the information and
documentation content for successful installation and registration by Microsoft’s Visual Studio
help system.
• <ProjectName>.cab (compiled help .mshc in digitally signed CAB file)
• helpcontentsetup.msha (product manifest providing help system installation information)

Intergraph Smart™ 3D .NET Programmer’s Guide 11


Getting Started

1. Select Disk for your installation source.


2. Browse to the location of the helpcontentsetup.msha file for your help documentation.
That folder must also contain its associated CAB file. Note: These files are delivered in
the Smart 3D programming \SOM folders for each .NET API project.
3. Select the file.

12 Intergraph Smart™ 3D .NET Programmer’s Guide


Getting Started

4. Click Open. This places your specified helpcontentsetup.msha file path in the installation
source.

5. Click Add in the Action column, which changes the Action command to Cancel.
6. On the window’s lower right, click Update, which opens the Security Alert for the
digitally signed CAB file.

7. Click Yes to proceed and update the local library. Now the CAB file package is installed
and merged with other Intergraph and Microsoft indexes and installed content.

Intergraph Smart™ 3D .NET Programmer’s Guide 13


Getting Started

8. See the Contents section automatically update to display your set of documentation for
review.

14 Intergraph Smart™ 3D .NET Programmer’s Guide


3D Three-Tier Architecture

3D Three-Tier Architecture
The software has an architecture that is component-oriented and built on three tiers.
The three-tier architecture of the 3D software includes the client, middle, and server tiers. These
tiers separate the graphical user interface, or GUI, stored in the client tier, from the business
logic in the middle tier. The business logic is further separated from the physical database in the
server tier.
The architecture emphasizes programming ease in producing functionality for the client tier. The
client tier mainly consists of commands, plus some components, ActiveX controls, and services.

Intergraph Smart™ 3D .NET Programmer’s Guide 15


3D Three-Tier Architecture

Client Tier
The client tier's functionality is loaded on user demand in the form of tasks, services, and
commands.
The client tier contains the menus, toolbars, views, dialog boxes, and frames. In the client tier,
you can manipulate the GUI with services, such as the SelectSet and GraphicViewMgr, and
with software-supplied components, such as locators, highlighters, and view manipulations.
A set of commands make up each task in the client tier. Eighty to ninety percent of the code in a
task is written in the form of a command or to support a command.
Each task has its own COMponent called the EnvironmentMgr and an associated XML file.
This XML file defines the look and feel for the task and specifies the services that it uses.
Services and other components support the commands and tasks by providing a set of
commonly-used functionalities. Services should respond to task switches. When a task starts or
ends, services are notified of the event to initialize or to clean up.
A service implements one or more service-specific interfaces. Generally, a service wraps a
specific bit of re-usable functionality. A service exists as a singleton, which is the one and only
instance of its class.

16 Intergraph Smart™ 3D .NET Programmer’s Guide


3D Three-Tier Architecture

Middle (Business) Tier


A task and its commands manipulate business objects. Business objects correspond to real-world
things such as pipes, pumps, tanks, hulls, decks, propellers, engines, and so forth and they
populate the middle tier.
Relationships define how business objects interact with each other. The following are examples
of this interaction:
A pipe might need to be parallel to another pipe.
A propeller might require an engine to exceed some threshold horsepower.
A deck must maintain a minimum distance from the decks above and below it.
Relationships are the software business rules. Relationships react to changes as they take place,
ensuring referential integrity and data consistency. Relationships and business objects are closely
tied to each other and the tasks that define and manipulate them. A task or set of closely-related
tasks defines business objects and relationships.
The RevisionMgr is a middle tier component that manages the associative relationships between
the objects and is the center of any engineering solution. This service continuously keeps every
entity consistent with all other data in the system. This consistency is defined by the relationships
of the entities.
The RevisionMgr works in cooperation with the business objects and relationships by detecting
changes to business objects. Using the relationships that business objects are involved in, the
RevisionMgr declares changes to any business objects defined as outputs of the relationships.
The RevisionMgr continues this promulgation until all affected business objects are up-to-date.
The RevisionMgr notifies the TransactionMgr, a client tier service, after all affected business
objects have been modified. The TransactionMgr in turn notifies any client tier services that are
listening.

Intergraph Smart™ 3D .NET Programmer’s Guide 17


3D Three-Tier Architecture

Server Tier
The server tier is made up of one or more physical datastores.
The server tier also provides storage for the metadata, which contained in the Repository.
Metadata, is the total description of all the classes, interfaces, relationships, and semantics in the
system.
The RevisionMgr service in the middle tier accesses this metadata.

18 Intergraph Smart™ 3D .NET Programmer’s Guide


Architecture in Smart 3D .NET

Architecture in Smart 3D .NET


The client-middle-server tier separation which exists in the 3D software is enforced in the .NET
programming layer. For example, the middle tier cannot access client tier components.
3D business objects come into existence when they are accessed and initiate a transaction with a
Start and Commit or Abort. Developers are concerned with the Commit and Abort actions
ensuring that the object reference has been cleared.
Standard Automation object models, such as Intergraph’s SmartSketch, use a typical object
collection and creation methodology paradigm. Collections of similar objects are maintained in
the model. New objects are created against these collections.
With the 3D software consisting of such large datasets, the .NET layer relies on relationship
connections to navigate ownership of information and filters to organize groups of objects. So
the valid state of the 3D object model is not represented by the paradigm of collection hierarchies
in .NET, but by relationships whose memberships are enforced by a large set of semantics.
Note that sometimes a collection cannot be modified in this new programming environment. A
.NET generic collection is available for this purpose, for example:
Public ReadonlyDictionary <ClassInformation> Classes;
Metadata tracks the classes and user attributes, so together with the 3D software client and
middle tier functionality, you can perform programming tasks in the COM world and now in a
simpler easier-to-use .NET programming layer.

Intergraph Smart™ 3D .NET Programmer’s Guide 19


Architecture in Smart 3D .NET

Interfaces and Class Implementation


For the most part the 3D software has been developed with interfaces separate from the
implementation. For .NET, certain criteria are considered when using an interface definition or
class definition.
• The interface is defined separately if it is intended to be implemented in distinct non-
hierarchical classes.
• Interfaces are defined for polymorphisms where a definite polymorphism is required,
and where strict inheritance is not adequate.
The .NET layer primarily consists of classes. Class inheritance exists where necessary.
BusinessObject is the parent class of all the 3D business object wrappers. Note that
BusinessObject is not a creatable object. Constructors are available so that business objects
created can be persisted into the database.

20 Intergraph Smart™ 3D .NET Programmer’s Guide


Architecture in Smart 3D .NET

Polymorphism
The .NET wrappers for the Smart 3D business objects use class inheritance from
BusinessObject to realize individual business objects. BusinessObject provides access to
properties and relationships, including ownership and states of the COM interface IJDObject.
Like the underlying 3D COM model, the .NET layer achieves polymorphism by implanting
interfaces. .NET provides helper implementations to which .NET wrappers delegate
implementations of the polymorphic interfaces.

Intergraph Smart™ 3D .NET Programmer’s Guide 21


Namespaces and Assemblies

Namespaces and Assemblies


.NET allows you to group your code into logical units. First, by grouping code in assemblies,
you can establish security, version, reference, and deployment boundaries. Second, by grouping
classes into namespaces, you can create a hierarchy in which it's easy to identify classes by their
fully qualified names. These two methods of organization complement one another, and you
need to use both of them in your own .NET development.
You can use .NET to create both assemblies and namespaces. It’s important to understand both
of these concepts to be a successful .NET developer.

22 Intergraph Smart™ 3D .NET Programmer’s Guide


Namespaces and Assemblies

Namespaces
A namespace is simply a collection of different classes. All Visual Studio applications are
developed using classes from the .NET System namespace. The namespace with all the built-in
Visual Studio functionality is the System namespace. All other namespaces are based on this
System namespace and is the basic namespace used by every set of .NET code.
Namespaces are a way of grouping type names and reducing the chance of name collisions. A
namespace can contain both “other” namespaces and types. The full name of a type includes the
combination of namespaces that contain that type.
You're probably already familiar with namespaces in the .NET Framework Class Library. For
example, the Button type is contained in the System.Windows.Forms namespace. This means
that the Button class is contained in the Forms namespace, which is contained in the Windows
namespace, which is contained in the root System namespace.
The fully qualified name of a class is constructed by concatenating the names of all the
namespaces that contain the type. For example, the fully qualified name of the Microsoft Button
class is System.Windows.Forms.Button. The namespace hierarchy helps distinguish types with
the same name from one another. For example, you might define your own class named Button,
but it might be contained in the ControlPanel namespace within the PowerPlant namespace,
making its fully qualified name PowerPlant.ControlPanel.Button.
There's no need to use fully qualified names in your code unless you need to resolve an
ambiguity between two types with the same type name used in the same project.

Smart 3D .NET Software Namespaces


Following Microsoft’s hierarchical rules for namespaces, Intergraph has adopted a logical
naming convention that allows for any product group to create their own namespaces with an
easily identifiable class structure.
Examples of 3D .NET software namespaces are:
• Ingr.SP3D.Common.Middle
• Ingr.SP3D.Common.Exceptions
• Ingr.SP3D.Common.Middle.Services
• Ingr.SP3D.Common.Client
• Ingr.SP3D.Equipment.Middle
• Ingr.SP3D.ReferenceData.Middle

Intergraph Smart™ 3D .NET Programmer’s Guide 23


Namespaces and Assemblies

Assemblies
An assembly is a collection of types and resources that form a logical unit of functionality. All
types in the .NET framework must exist in assemblies.
An assembly is the building block of a .NET application. It is a self-describing collection of
code, resources, and metadata. Assemblies take the form of a dynamic link library (.dll) or an
executable program (.exe), but they differ as they contain the information found in a type library
and the information about everything else needed to use an application or component.
Assemblies are made of two parts - manifest and modules. The manifest contains information
about what is contained within the assembly. The modules are internal files of intermediate
language (IL) code which are ready to run. When programming, it is not required to directly deal
with assemblies as the common language runtime (CLR) and the .NET framework do the job
behind the scenes. The assembly file is visible in the Solution Explorer window of the project.
An assembly includes:
• Information for each public class or type used in the assembly including class or type
names, the classes from which an individual class is derived, etc.
• Information on all public methods in each class, such as the method name and return
values (if any).
• Information on every public parameter for each method, such as the parameter's name
and type.
• Information on public enumerations including names and values.
• Information on the assembly version (each has a specific version number).
• Intermediate language code to execute.
• A list of types exposed by the assembly and a list of other assemblies required by the
assembly
Smart 3D .NET Assemblies
Examples of 3D .NET assemblies corresponding with their proper namespaces are:
• CommonMiddle.dll
• SystemMiddle.dll
• EquipmentMiddle.dll

24 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Creating Commands
To create .NET-based commands that can execute in the 3D software, you must create a class
that subclasses from one of the base command classes provided in the 3D object model. This
approach to writing commands is significantly different from the way commands were written in
the 3D software COM world.
Commands historically have been written in Visual Basic (VB). Since VB 6 had no provision for
subclassing, it was necessary to always write a command “from scratch”, creating a VB class
that implemented the IJCommand2 interface. There was no way to take advantage of commonly
used functionality by using inheritance. Instead, a fairly hefty Command Wizard was provided
that created all the boilerplate code that might be applicable to the command being written:
GraphicView event handlers, SmartStep construction, converting world coordinates to screen
coordinates, etc.
With the advent of .NET, and especially its Common Runtime, it is possible to provide reusable
command functionality in the form of base classes. These base classes, though written in C#, are,
through the Common Runtime, seamlessly available to command writers in any supported .NET
language (specifically, to command writers who choose to use Visual Basic .NET).

Intergraph Smart™ 3D .NET Programmer’s Guide 25


Creating Commands

Types of Commands
There are four types of commands used in the 3D software:
• Menu Handler Commands
• Modal Commands
• Graphic Commands
• Step Commands

Menu Handler Commands


A menu handler command is best thought of as the way traditional commands are implemented
in Windows. The user clicks on a menu item (or an associated button on a toolbar), and the menu
(or button) window event handler is invoked. The command processing takes place within the
body of that event handler.
While rare in the 3D software, there are examples of menu handler commands. File operations,
for instance, are all done in situ as part of a menu handler. Note that menu handler commands are
not separate objects, but instead merely methods.

Object-Based Commands
Most commands in the 3D software, however, are implemented as COM objects, and exist
(execute) as separate entities. They are ultimately started as the result of a menu handler, but in
most cases, the menu handler is the same function: NormalCmd, which takes as an argument
(passed in by the MenuHandler service) the ProgID of a class (HighCommand is another menu
handler that operates exactly as NormalCmd, except it starts the command with high priority).
This ProgID is passed in turn to the CommandManager service, which creates an instance of
the class, and transfers control to the object, which in turn executes the command.
These COM objects all support the IJCommand2 interface, by which the CommandManager
controls the commands execution. It invokes Start, Stop, Suspend and Resume methods on the
command object.
It is these COM object commands that form the real basis of commands in the 3D software.
There is no support, per se, in the .NET base classes for menu-handler commands. Modal,
graphic, and step commands are all separate objects, and are described in the following sections.

.NET Command Methods & Properties


All commands in the 3D software implement the IJCommand2 COM interface, and just because
commands are .NET does not obviate them from this requirement. And yet a cursory inspection
of base classes reveals that these .NET classes do not in fact implement any such interface.
The reason they do not is when CommandManager starts a .NET command, it first creates a
COM wrapper that implements IJCommand2. The wrapper in turn creates the .NET class.
CommandManager subsequently deals with the intermediate command exactly as if it were a

26 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

COM command, and the wrapper, when invoked by CommandManager at its various entry
points, in turn calls the corresponding .NET class method.
The following table shows the correspondence between IJCommand2 methods and properties
and their counterparts in the .NET command class. Note that the .NET method names are, in
accordance with .NET principles, given names like OnStart (rather than Start), signifying their
reactive nature.
Hereafter, reference is made only to the .NET methods, since that is the primary focus of this
section.

3D IJCommand2 Method .NET Command Class Method

Start OnStart

Stop OnStop

Suspend OnSuspend

Resume OnResume

OnIdle OnIdle

3D IJCommand2 Property .NET Command Class Property

EnableUIFlags EnableUIFlags

Modal Modal

Suspendable Suspendable

Running Running

EnableViewType not currently supported

EnableSpecial not currently supported

ClientServiceProvider
In addition to inherited functionality, much of the activity performed by commands involves
client level services. You can access these services from the static class, ClientServiceProvider.
ClientServiceProvider provides direct access to the following client services:

Service Notes

TransactionMgr Commit or abort changes to the model.

GraphicViewMgr Control the views and create hiliters.

Preferences Set or get application preferences.

Intergraph Smart™ 3D .NET Programmer’s Guide 27


Creating Commands

ValueMgr Access to application global data.

SelectSet Access and manipulate the select set.

WorkingSet Access the current model working set.

Modal Commands
Modal commands are distinguished by the fact that after the Start method is called, the
command is immediately terminated. The modality is usually exemplified by the fact that the
command puts up a modal dialog with which to interact with the user (i.e., a dialog is not always
present; the Delete command is a modal command that runs without the need for a dialog.).
When the CommandManager runs a modal command (as determined by the value of the Modal
property), it first calls the OnStart method, and upon return from that, it immediately calls the
OnStop method, and then deletes the command object. Thus, all the work of the command is
done in the OnStart method. This usually consists of displaying a modal (!) dialog. After the
user presses OK or Cancel, the command may do some cleanup, and then return control to the
CommandManager. The essential parts of a modal command are therefore usually embedded in
the logic of the dialog.

Graphic Commands
Graphic commands (also called event-driven commands) differ from modal commands in that
the CommandManager does not terminate the command after the OnStart method is invoked.
Rather, the CommandManager relinquishes control back to the 3D software. Subsequently,
windows events arrive at the graphic command’s event handlers (generally these are
MouseDown, MouseMove, and MouseUp, but others may be handled). The command uses
these events to drive its internal logic. This usually consists of locating and hiliting graphics in
the graphic display, dynamically moving objects around, perhaps constructing new 3D business
objects, etc.
Eventually, the logic of the command is satisfied, and it terminates itself by calling the
StopCommand method (available to 3D .NET-based commands). Alternatively, it may be
stopped if another command of the same priority is started (e.g., the user clicking on a menu item
or toolbar button).
Optionally, graphic commands can be suspended:
• If their Suspendable property is true (the command determines whether it is suspendable
or not).
• Only if a command of higher priority is started. Examples of high priority commands are
View manipulation commands. When a higher priority command is started, and if the
command is Suspendable, CommandManager calls the OnSuspend method. As a
response to this call, the command takes steps to become inactive (i.e., not respond to
events). Eventually, the higher priority command terminates, upon which the original
command is invoked on its OnResume method. At that time, it restores itself and again
responds to events.

28 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Step Commands
Step commands are a special case of graphic commands. They respond to events, but in addition
can define a number of steps or states. The command logically progresses from step to step as
part of its execution, perhaps going backwards, but generally arriving at some final step.
Step commands are quite common in the 3D software. They are often used in construction
workflows. For example, an initial step might locate an existing object, such as a pump. The next
step could locate another pump, and then the final step could route a pipe from the first pump to
the second. The command might then terminate, or perhaps return to the first step and begin the
process again. The steps and the logic can get quite complex, but organizing into specific steps
makes the command easier to deal with, both from the end user’s and programmer’s perspective.

Intergraph Smart™ 3D .NET Programmer’s Guide 29


Creating Commands

Command Assistants
Command assistants are a concept in the 3D software whereby a command-like object is started,
and then runs in the background. Normally, only a single command is allowed to run, but there
are situations where it is useful for something to be running all the time. For instance, a
command assistant might follow mouse moves while preforming locates, and then continuously
report feedback to the user.
Command assistants are, for all practical purposes, exactly like commands. That is, they are
manipulated by the same interface. Thus, a 3D .NET-based command could act as a command
assistant. However, there is currently no way to start a .NET-based command assistant.
Depending on evolving requirements, this may change in the future.

Committing Transactions
A fundamental rule in the 3D software is this - changes to the database can only be made in
commands running at normal priority.
More specifically, commands not running at normal priority (and all command assistants) cannot
issue a TransactionManager command of Commit or Abort. Since modifying an object
implicitly involves a transaction in the software, only commands running at normal priority can
alter any business object.
Important: Failure to abide by this rule can result in database corruption.

Terminating Commands
A command may choose to stop itself. This should always be done by invoking the base class
StopCommand method. This is the only fully supported way for a command to terminate itself.
Invoking this method ensures that the command will be terminated in an orderly manner, and
that all entities, which base classes have brought into play on behalf of the command, are
properly terminated as well.

30 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Creating a Command Solution and Project


A command is a .NET class. In order to create a new command, you need a .NET project in
which to develop the class code. Begin by using Visual Studio 2013 to create a C# or VB class
library project. The following example shows how to create a new solution (and its project) for a
project called MyNewCommand. In this case, the language is Visual C#, but of course Visual
Basic is also valid.

Intergraph Smart™ 3D .NET Programmer’s Guide 31


Creating Commands

In order to use any 3D .NET base class, you need to add references to the assembly that contains
those base classes. After creating the project, right mouse click on the References node for the
project in the Solutions Explorer pane. Click Add Reference.

32 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Click Browse…, and navigate to the 3D software SxS\Intergraph folder.

Note: The location of this folder varies depending on your software installation location. The
Add Reference dialog pictured shows the location for software delivered for Intergraph
developers. Generally, you can find these assemblies in {Product
Path}\Core\Container\Bin\SxS\Intergraph folder, where {Product Path} refers to the delivery
location of the software.
Select the Intergraph.Common.Toolkit.Client.dll and click Add.

Intergraph Smart™ 3D .NET Programmer’s Guide 33


Creating Commands

Click Browse… again. This time, navigate to the 3D software {Product


Path}\Core\Container\Bin\Assemblies\Release folder.

Note in this example that both CommonClient and CommonMiddle are selected. The base
classes are located in CommonClient, but any command that does much more than “Hello,
World” usually requires CommonMiddle as well. Furthermore, you most likely need to
reference other assemblies. For example, if your command manipulates Equipment entities, you
need EquipmentMiddle (where 3D .NET wrappers for the Equipment business object are
located). You can add or remove references at any time.

34 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Results of your selections will be listed and checked in the Recent pane of the Reference
Manager.

Intergraph Smart™ 3D .NET Programmer’s Guide 35


Creating Commands

Writing Commands: Modal Command


This section discusses the process for writing a modal command. Many of the initial steps are
common to all commands (i.e., the class name, adding references and using or Imports
statements), and may not be repeated when other commands are discussed.

Common Class File Setup


.NET requires that, in addition to adding an assembly reference to the project for external, you
need to add statements to the source file that declare your intent of using the objects for certain
namespaces. In this case, you add using statements (C#) or Imports (VB). These statements
should precede the class declaration.
[C# example]
using Ingr.SP3D.Common.Client; // To access command base
classes
using Ingr.SP3D.Common.Client.Services; // TransactionMgr, etc.
using Ingr.SP3D.Common.Middle; // To access other useful
objects

[VB example]
Imports Ingr.SP3D.Common.Client
Imports Ingr.SP3D.Common.Client.Services
Imports Ingr.SP3D.Common.Middle
Note that the default namespace for the newly created project is “MyNewCommand” (i.e., the
name of the project). The Create Project dialog also created a new class, called “Class1”.
Change the class name to something appropriate, such as, “MyModalCommand”:
[C# example]
public class MyModalCommand
{
}

[VB example]
Public Class MyModalCommand

End Class

36 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Note that you can also simply delete the default new class (Class1.cs or Class.vb), and then
create a new class with the appropriate name. Right mouse click on the project in the Solutions
Explorer pane, and click Add… and select Class. In the Templates: pane, select Class, then
provide the name, for example, “MyModalCommand”. For C#, the dialog looks like this:

Now we are prepared to properly declare the class inheritance for a modal command. Edit the
class statement to provide the proper base class; in this case BaseModalCommand.
[C# example]
public class MyModalCommand : BaseModalCommand
{
}

[VB example]
Public Class MyModalCommand
Inherits BaseModalCommand
End Class
At this point, you actually have a functioning command, although one that does very little. But
this code can be compiled, and it can run properly and without error. This is because
BaseModalCommand provides stubs for all the required command methods, and can properly
start and shut down the command without further coding.

Intergraph Smart™ 3D .NET Programmer’s Guide 37


Creating Commands

The key to writing commands in .NET is to provide overrides for only those methods that are
relevant for your work. For a modal command, that is likely to involve only the OnStart
method.

BaseModalCommand Utility Methods


BaseModalCommand is the class at the root of all .NET-based 3D software commands. In
addition to providing basic command interaction (OnStart, OnStop, etc), it also provides a few
utility methods, which are commonly used in any command. These include:

Method Notes

WriteStatusBarMsg Writes text to the status bar.

StopCommand Used to self-destruct; i.e., terminate the current


command.

DebugLogMessage Writes a message to the DebugLog service.

“Hello World”: The Simplest Command


.NET-based 3D software commands obtain much of their power by using inherited methods
made available by the base class. In this example, we use those to write “Hello World.”
First, provide an override for the OnStart method.
[C# Example]
public override void OnStart(int commandID, object argument)
{
base.OnStart(commandID, argument);
}

[VB Example]
Public Overrides Sub OnStart(ByVal commandID As Integer, _
ByVal argument As Object)
MyBase.OnStart(commandID, argument)
End Sub
Now use the inherited method WriteStatusBarMsg to do the work:
[C# Example]
base.WriteStatusBarMsg("Hello World");

[VB Example]
MyBase.WriteStatusBarMsg "Hello World"

You have now created a simple modal command.

A Real World Example


A more pertinent example is provided here. In this command, we create a filter and use it to
obtain a set of objects. Then we either delete or modify the objects obtained, based on a property
setting.

38 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Create a new command (either C# or VB) using Project > Add Class…. Name it FilterSieve.
Complete all the class preparation as described above (adding using or Imports statements for
CommonClient and CommonMiddle and properly subclassing from BaseModalCommand).
Provide an override for the OnStart method. Now, create a new Filter, and set the definition to
filter all Equipment objects:
[C# Example]
Filter filter = new Filter();
filter.Definition.AddObjectType("Equipment&Furnishing");

[VB Example]
Dim filter As New Filter()
filter.Definition.AddObjectType "Equipment&Furnishing"
In order to apply the filter (which returns a read-only collection of BusinessObjects), you’ll need
to add a using/Import statement:

[C# Example]
using System.Collections.ObjectModel; // To access
ReadOnlyCollection<T>

[VB Example]
Imports System.Collections.ObjectModel ' To access
ReadOnlyCollection<T>
Now add a statement to apply the filter and obtain the resulting objects. By default, Filter.Apply
operates on the current model database connection:
[C# Example]
ReadOnlyCollection<BusinessObject> results = filter.Apply();

[VB Example]
Dim results As ReadOnlyCollection(Of BusinessObject)
results = filter.Apply
Now iterate through the results collection. For the purposes of this exercise, we use generic
property access and look at the name of the object with the IJNamedItem COM interface. If it’s
not named, or if the name begins with “BAD”, we delete the object:
[C# Example]
foreach (BusinessObject businessObject in results)
{
var namePropertyValue =

(PropertyValueString)businessObject.GetPropertyValue("IJNamedItem",
"Name");
if (namePropertyValue == null ||
namePropertyValue.PropValue.StartsWith("BAD"))
{
businessObject.Delete();
}
}

Intergraph Smart™ 3D .NET Programmer’s Guide 39


Creating Commands

[VB Example]
For Each businessObject As BusinessObject In results
Dim namePropertyValue As PropertyValueString = _
DirectCast(businessObject.GetPropertyValue("IJNamedItem",
"Name") "), PropertyValueString)
If namePropertyValue Is Nothing Then
businessObject.Delete()
ElseIf namePropertyValue.PropValue.StartsWith("BAD") Then
businessObject.Delete()
End If
Next
Finally, use the TransactionManager to commit the changes to the database:
[C# Example]
ClientServiceProvider.TransactionMgr.Commit("FilterSieve");
[VB Example]
ClientServiceProvider.TransactionMgr.Commit("FilterSieve")
The whole source looks like this:
[C# Example]
public override void OnStart(int commandID, object argument)
{
base.OnStart(commandID, argument);

Filter filter = new Filter();


filter.Definition.AddObjectType("Equipment&Furnishing");
ReadOnlyCollection<BusinessObject> results = filter.Apply();
foreach (BusinessObject businessObject in results)
{
var namePropertyValue = (PropertyValueString)
businessObject.GetPropertyValue("IJnamedItem", "Name");
if (namePropertyValue == null ||
namePropertyValue.PropValue.StartsWith("BAD"))
{
businessObject.Delete();
}
}
ClientServiceProvider.TransactionMgr.Commit("FilterSieve");
}

[VB Example]
Public Overrides Sub OnStart(ByVal commandID As Integer, _
ByVal argument As Object)
MyBase.OnStart(commandID, argument)

Dim filter As New Filter()


filter.Definition.AddObjectType("Equipment&Furnishing")
Dim results As ReadOnlyCollection(Of BusinessObject)

40 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

results = filter.Apply
For Each businessObject As BusinessObject In results
Dim namePropertyValue As PropertyValueString = _
DirectCast(businessObject.GetPropertyValue("IJNamedItem", _
"Name"), PropertyValueString)
If namePropertyValue Is Nothing Then
businessObject.Delete()
ElseIf namePropertyValue.PropValue.StartsWith("BAD") Then
businessObject.Delete()
End If
Next
ClientServiceProvider.TransactionMgr.Commit("FilterSieve")
End Sub

Intergraph Smart™ 3D .NET Programmer’s Guide 41


Creating Commands

Writing Commands: Graphic Command


Graphic commands generally have less to do in the OnStart method, concentrating instead on
the event handlers. The BaseGraphicCommand class is, first of all, subclassed from
BaseModalCommand. Therefore it (and all subclasses) inherits the utility methods provided by
the parent class. In addition, BaseGraphicCommand adds a couple of utility methods and
properties of its own, geared more toward graphic processing. These include:

Method Notes

XformWorldToScreen Convert coordinates from World to Screen.

XformScreenToWorld Convert coordinates from Screen to World.

Property Notes

AllowEvents Set to enable or disable events from being


delivered to event handlers (see below).

CurrentView The active view from which events are


generated.

PreviousView The most recent view prior to the current view.


May be null (no previous view).

RibbonBar Gets or sets the ribbon bar control for this


command.

The BaseGraphicCommand class has a series of virtual (and hence, overridable) methods that
are called in response to a small set of graphics events. The decision was made in designing this
class that 95% of all 3D software event-driven commands deal only with MouseDown,
MouseMove and MouseUp. A handful of others deal with keyboard events. Thus, the number of
available events in BaseGraphicCommand is quite a bit smaller than in the corresponding
COM world.
The event handler methods include:
• OnMouseDown
• OnMouseMove
• OnMouseUp
• OnKeyDown
• OnKeyUp
A graphic command merely overrides the event handling methods that it cares about, and ignores
the others.

42 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Behind the scene, BaseGraphicCommand does both pre- and post-processing for all of these
events. For example, it keeps up with the active view (the view that generated the event and sets
the value of CurrentView based on whether the view changed since the last event was handled).

A Graphic Command Example


As an example, let’s develop a command that handles MouseMove and MouseUp. On
MouseMove, it will perform a locate into the model and hilite any objects that are located. On
MouseUp, it will locate and add any objects located to the SelectSet.
Create a new command class called GraphicLocate and complete the appropriate class source
fix up (using or Imports, etc.). Be sure to add a statement for the
System.Collections.ObjectModel namespace since you are dealing with business object
collections and Ingr.SP3D.Common.Client.Services for the graphic hiliter. Instead of
BaseModalCommand, use BaseGraphicCommand as the parent class.
[C# example]
public class GraphicLocate : BaseGraphicCommand
{
}

[VB example]
Public Class GraphicLocate
Inherits BaseGraphicCommand
End Class
Declare a class variable for a Hiliter and in the OnStart method, create a new Hiliter from the
GraphicViewManager, and set its color. Note the use of the .NET ColorConstants construct to
provide pre-defined color constants:
[C# example]
public class GraphicLocate : BaseGraphicCommand
{
private GraphicViewHiliter hiliter = null;
public override void OnStart(int commandID, object argument)
{
base.OnStart(commandID, argument);
hiliter = new GraphicViewHiliter();
hiliter.Color = ColorConstants.RGBGreen;
}
}

[VB example]
Public Class GraphicLocate
Inherits BaseGraphicCommand
Private m_hiliter As GraphicViewHiliter
Public Overrides Sub OnStart(ByVal commandID As Integer, _
ByVal argument As Object)
MyBase.OnStart(commandID, argument)
m_hiliter = New GraphicViewHiliter()
m_hiliter.Color = ColorConstants.RGBGreen
End Sub

Intergraph Smart™ 3D .NET Programmer’s Guide 43


Creating Commands

End Class
Now provide overrides for OnMouseMove and OnMouseUp. In OnMouseMove, use the
CurrentView to locate, and then hilite anything located. In OnMouseUp, locate again, and add
to the select set anything located. Note that, since the boreline locate can locate things on top of
one another, you could potentially add multiple things to the select set.
[C# example]
protected override void OnMouseMove(GraphicView view,
GraphicViewManager.GraphicViewEventArgs e, Position position)
{
base.OnMouseMove(view, e, position);
Locator locator = CurrentView.CreateLocator();
locator.Locate(e.X, e.Y, 1.0);
if (locator.LocatedObjects.Count > 0)
{
_hiliter.HilitedObjects.Clear();
_hiliter.HilitedObjects.Add(oLocator.LocatedObjects);
}
}
protected override void OnMouseUp(GraphicView view,
GraphicViewManager.GraphicViewEventArgs e, Position position)
{
base.OnMouseUp(view, e, position);
Locator locator = CurrentView.CreateLocator();
locator.Locate(e.X, e.Y, 1.0);
if (locator.LocatedObjects.Count > 0)
{
ClientServiceProvider.SelectSet.SelectedObjects.Add
(locator.LocatedObjects);
}
}
[VB example]
Protected Overrides Sub OnMouseMove( _
ByVal view As GraphicView, _
ByVal e As GraphicViewManager.GraphicViewEventArgs, _
Position As Position)
MyBase.OnMouseMove(view, e, position)
Dim locator As Locator
locator = MyBase.CurrentView.CreateLocator()
locator.Locate(e.X, e.Y, 1.0)
If (locator.LocatedObjects.Count > 0) Then
m_hiliter.HilitedObjects.Clear()
m_hiliter.HilitedObjects.Add(locator.LocatedObjects)
End If
End Sub
Protected Overrides Sub OnMouseUp( _
ByVal view As GraphicView, _
ByVal e AsGraphicViewManager.GraphicViewEventArgs, _
Position As Position)
MyBase.OnMouseUp(view, e, position)
Dim locator As Locator

44 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

locator = MyBase.CurrentView.CreateLocator()
locator.Locate(e.X, e.Y, 1.0)
If (locator.LocatedObjects.Count > 0) Then
ClientServiceProvider.SelectSet.SelectedObjects.Add _
(locator.LocatedObjects)
End If
End Sub

Intergraph Smart™ 3D .NET Programmer’s Guide 45


Creating Commands

Writing Commands: Step Command


BaseStepCommand subclasses from BaseGraphicCommand, and so inherits all the preceding
utility methods and properties. In addition, StepCommand adds several properties necessary for
defining and implementing a step command. These include:

Property Notes

CumulativeSelection Returns business objects selected during the


lifetime of the command.

CurrentStep Gets the current step.

CurrentStepIndex Gets or sets the current step index.

Enabled Toggles whether a command is enabled.

GlobalExcludedFromLocate Gets the collection of business objects that are


excluded from locate for all steps.

LocateHiliterColor Gets or sets the color of hiliter used when


locating objects.

LocateHiliterWeight Gets or sets the weight of hilter used when


locating objects.

PointCreator Sets a point creator object.

SelectHiliterColor Gets or sets the color of hiliter used when


objects are selected.

SelectHiliterWeight Gets or sets the weight of hilter used when


objects are selected.

StepCount Gets or sets the number of steps.

Steps Gets the collection of steps.

These methods are also available on the BaseStepCommand class:

Method Notes
GetSolvedConstraints Returns the collection of constraints used by
SmartSketch3D.
UpdateStep Reprocesses current step data using the step
settings.

46 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Behind the scene, BaseStepCommand does both pre- and post-processing for all graphic events.
The developer is able to concentrate on the results of each step, and not be concerned with
specifics of locating, selecting, etc.
BaseStepCommand also adds a set of event handler methods similar to those supplied by
BaseGraphicCommand. A step command overrides the event handler methods that it cares
about, and ignores the others. The event handler methods are described as follows:
OnObjectsLocated
This method is called when business objects are located during MouseMove. This provides a
way for subclasses to filter the objects located by SmartSketch3D. This method is invoked
before OnMouseMove. Two arguments are passed in.
BOCollection Collection of objects that have been located.
oLocatedBusinessObjects

ref bool Boolean that indicates whether the located objects


bIgnoreLocatedBusinessObjects need to be processed to generate SmartSketch3D
constraints. Default value is false, in which all located
objects are processed by SmartSketch3D. The
overriding method sets this, and it is interpreted by
BaseStepCommand.

OnSmartSketchConstraintConflict
This method is called when a SmartSketch3D constraint is added that conflicts with an existing
constraint. The one argument is:
Constraint conflictingConstraint ‘The constraint that was added.
The overriding method might react, for example, by removing the offending constraint or
possibly some other constraint.
OnSmartSketchPositionChange
This method is called when SmartSketch3D has snapped the mouse position based on the
current set of constraints. There are two arguments:
Position oPosition Modified position (read-only).
MouseEvent eventMouse The mouse event that caused the
PositionChange (MouseMove or MouseUp).

OnStepSelectionChanged
This method is called when the step's selection is changed. There are four arguments:

Intergraph Smart™ 3D .NET Programmer’s Guide 47


Creating Commands

StepDefinition The step with SelectionInfos collection is modified.


stepDef

Bool isSelected When true, BusinessObject and Position pair are selected.
BusinessObject The business object that was selected or deselected.
businessObj

Position position Position that corresponds to the BusinessObject that was


selected or deselected. When selections are made in a step that
employs SmartSketch3D, then it is possible that the object
selected can have an associated position determined by
SmartSketch3D (if SmartSketch3D is not used by the step, the
arguments dealing with position are not used and should be
ignored). The isSelected argument returns whether the Position
argument is valid.

OnStepPostSelectionChanged
This method is called after OnStepSelectionChanged has occurred. The one argument is the
step in which the SelectionInfos collection is modified.

A Step Command Example


Let’s build a command with a series of the following steps:
1. Select one Equipment object, hiliting only Equipment objects and using QuickPick to
disambiguate among multiple located objects.
2. Excludes the object selected in step (1), and selects one or more different objects.
3. If the objects in step (2) support IJNamedItem, reports how many of those objects have
the same first letter as the first letter of the Equipment selected in step (1).
It’s not a particularly useful command, but it provides an example of several pieces of step
command functionality.
Create a new command called NameChecker and complete the standard source code editing.
Define the parent class as BaseStepCommand:
[C# example]
public class NameChecker : BaseStepCommand
{
}

[VB example]
Public Class NameChecker
Inherits BaseStepCommand
End Class
In the OnStart override, establish two steps.

48 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

[C# example]
public override void OnStart(int commandID, object argument)
{
base.OnStart(commandID, argument);
StepCount = 2;
Steps[0].Prompt = "Select one Equipment";
Steps[0].MaximumSelectable = 1;
Steps[0].LocateBehavior =
StepDefinition.LocateBehaviors.QuickPick;
Steps[0].StepFilter.AddInterface("IJEquipment");
Steps[1].Prompt = "Select as many things as you want.";
Enabled = true; // This starts the command.
}

[VB example]
Public Overrides Sub OnStart(ByVal commandID As Integer, _
ByVal argument As Object)
MyBase.OnStart(commandID, argument)
StepCount = 2
Steps(0).Prompt = "Select one Equipment"
Steps(0).MaximumSelectable = 1
Steps(0).LocateBehavior = _
StepDefinition.LocateBehaviors.QuickPick
Steps(0).StepFilter.AddInterface("IJEquipment")
Steps(1).Prompt = "Select as many things as you want."
Enabled = True
End Sub
Override OnMouseUp and check whether the current step is satisfied. If so, advance the step.
When the last step is completed, perform the name check.
[C# example]
protected override void OnMouseUp(GraphicView view,
GraphicViewManager.GraphicViewEventArgs e, Position position)
{
base.OnMouseUp(view, e);
// Anything selected?
if (Steps[CurrentStepIndex].SelectedBusinessObjects.Count > 0)
{
if (CurrentStepIndex == 0)
{
CurrentStepIndex++; // Bump to next step.
}
else
{
// Time to check; get Step 1 name.
int numberOfMatchingNames = 0;
BusinessObject oneBusinessObject =
Steps[0].SelectedBusinessObjects[0];
PropertyValueString stepOneName =
(PropertyValueString)
oneBusinessObject.GetPropertyValue

Intergraph Smart™ 3D .NET Programmer’s Guide 49


Creating Commands

("IJNamedItem", "Name");
// Now look for matches from Step 2.
foreach (BusinessObject businessObject in
Steps[1].SelectedBusinessObjects)
{
If (businessObject.SupportsInterface("IJNamedItem"))
{
PropertyValueString namePropertyValue =
(PropertyValueString)
businessObject.GetPropertyValue
("IJNamedItem", "Name");
if (namePropertyValue.PropValue[0] ==
stepOneName.PropValue[0])
{
numberOfMatchingNames++;
}
}
}
WriteStatusBarMsg(numberOfMatchingNames.ToString() +
"objects match criteria");
StopCommand(); // Kill the command.
}
}
}

[VB example]
Protected Overrides Sub OnMouseUp(ByVal view As _
GraphicView, ByVal e As _
GraphicViewManager.GraphicViewEventArgs, _
position As Position
MyBase.OnMouseUp(view, e, position)
If CurrentStepIndex = 0 Then
CurrentStepIndex = CurrentStepIndex + 1
Else
' Time to check; get Step 1 name.
Dim numberOfMatchingNames As Integer = 0
Dim oneBusinessObject As BusinessObject
oneBusinessObject = Steps(0).SelectedBusinessObjects(0)
Dim stepOneName As PropertyValueString
stepOneName = DirectCast( _
oneBusinessObject.GetPropertyValue("IJNamedItem", _
"Name"), PropertyValueString)

' Now look for matches from Step 2.


For Each businessObject As BusinessObject In _
Steps(1).SelectedBusinessObjects
If businessObject.SupportsInterface("IJNamedItem") Then
Dim namePropertyValue As PropertyValueString
namePropertyValue = DirectCast( _
businessObject.GetPropertyValue("IJNamedItem", "Name") _
PropertyValueString

50 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

If namePropertyValue.PropValue(0) =
stepOneName.PropValue(0) Then
numberOfMatchingNames = numberOfMatchingNames +1
End If
End If
Next
WriteStatusBarMsg(numberOfMatchingNames.ToString() + " objects
match criteria")
StopCommand() ' Kill the command.
End If
End Sub

Ribbon Bars
A ribbon bar is a toolbar on the S3DHost main window that is specific to the active command.
The ribbon bar lies just below the main S3DHost toolbar. Since it is specific to the active
command, the ribbon bar will generally change as the active command changes. If a command
does not need a ribbon bar, the ribbon bar area remains blank. The following illustration displays
the ribbon bar for the PointAlong command.

.NET graphic and step commands can employ a ribbon bar as follows:
1. Create a ribbon bar control. The control must be subclassed from the
BaseRibbonBarControl class.
2. Create an instance of the ribbon bar control.
3. Set the RibbonBar property (defined on the BaseGraphicCommand class) to the newly
created control.

BaseRibbonBarControl
The BaseRibbonBarControl class exists primarily to ensure that the RibbonBar property has a
specific signature. In the future, utility methods may be added to the class to aid in implementing
a ribbon bar, but for now, it mainly guarantees that the RibbonBar property has a well-defined
type. It also guarantees that the ribbon bar is properly disposed of when an instance is destroyed.
To create your own command ribbon bar, create a new class and subclass it from
BaseRibbonBarControl:
public partial class MyRibbonBar : BaseRibbonBarControl
The use of the partial keyword is typical in .NET when developing GUI elements. Part of the
GUI is kept in a “partial” segment, while operational code is written in another.

Intergraph Smart™ 3D .NET Programmer’s Guide 51


Creating Commands

Add whatever controls are deemed necessary for the ribbon bar. For instance, the following
example adds four text box controls and their associated labels:

In general, the ribbon bar also contains public methods and properties, which allow the command
to communicate. In the previous example, we might expect four properties allowing the
command to set and retrieve Distance, East, North, and Elevation values. For a step command,
the ribbon bar might offer a method (or property) that the command uses to change the step,
presenting a different set of prompts or controls. Finally, the ribbon bar can offer events that are
raised when the user interacts with the command. For example, if the user presses a button in
order to change step, the ribbon bar should raise an event back to the command.
In any case, after the ribbon bar has been constructed, the next effort is to set the ribbon bar for
the command. This is generally done in the command’s Start method:
[C# example]
// Set ribbon bar.
myRibbonBar = new MyRibbonBar();
base.RibbonBar = myRibbonBar;

[VB example]
‘ Set ribbon bar.
m_yRibbonBar = New MyRibbonBar()
Base.RibbonBar = m_yRibbonBar

The lifetime management of the ribbon bar is handled by the base class.

52 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Commands

Important Changes for CommonMiddle and


CommonClient
Changes with the CommonApp environment can affect CommonMiddle and CommonClient
projects requiring a recompile of existing projects.
• For any project using the existing UOMFormat class from CommonMiddle, that is
required to recompile for any reason, you must add the following reference to the project:
{Product
Path}\Smart3D\Core\Container\Bin\SxS\Intergraph\Intergraph.CommonToolkit.Middle.d
ll.
• For any project that contains a CommonClient reference, that is required to recompile
for any reason, you must add the following reference to the project:
{Product
Path}\Smart3D\Core\Container\Bin\SxS\Intergraph\Intergraph.CommonToolkit.Client.dl
l.

Intergraph Smart™ 3D .NET Programmer’s Guide 53


Creating Naming Rules

Creating Naming Rules


Introduction
NameRule is a component that can be customized by end-users to maintain a naming scheme for
objects.

Architecture
All .NET name rules must be subclassed from the NameRuleBase class, which is provided in
Ingr.SP3D.Common.Middle namespace of the CommonMiddle assembly.

NameRuleBase

Calls GetNamingParents and


ComputeName on Custom Inherits
SP3D NameRule
Custom NameRule

54 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Naming Rules

Base class - NameRuleBase


Name rules authored in .NET must implement the following abstract function and method
defined in the base class. The 3D software uses these to call into a name rule.
1. GetNamingParents function allows customization to return a collection of BusinessObjects
which can be used in the naming scheme of an entity.
public abstract Collection<BusinessObject>
GetNamingParents(BusinessObject oEntity);
2. ComputeName method allows customization to formulate a name based on a customer’s
naming scheme.
public abstract void ComputeName(BusinessObject oEntity,
ReadOnlyCollection<BusinessObject> oParents, BusinessObject
oActiveEntity);
The base class provides a set of commonly used functions and methods which help in developing
a name rule. Following are some examples:
1. protected void GetCountAndLocationID(string sBaseName, out long
lCount, out string sLocationID)
Returns a count (from name generator) and LocationID for the name string passed in.
2. protected string GetName(BusinessObject oBusinessObject)
Returns a name for the named business object passed in.
3. protected void SetName(BusinessObject oBusinessObject, string sName)
Sets a name on a named business object;
4. protected string GetNamingParentsString(BusinessObject
oActiveEntity)
Returns naming parents string or name basis for the active entity passed in.
5. protected void SetNamingParentsString(BusinessObject oActiveEntity,
string sNamingParentsString)
Sets naming parents string or name basis for the active entity passed in.
6. protected BusinessObject GetParent(HierarchyTypes oHierarchyType,
BusinessObject oChild)
Gets a parent business object for the child business object based on the HierarchyTypes
passed in. HierarchyTypes enumeration is defined in the Ingr.SP3D.Common.Middle
namespace as follows:
public enum HierarchyTypes
{
System = 1,
Assembly,
WBS,
Analysis,
Space,

Intergraph Smart™ 3D .NET Programmer’s Guide 55


Creating Naming Rules

PermissionGroup,
Volume_NamedSpace
}
The hierarchy type PermissionGroup is not supported and will throw
System.NotSupportedException.
7. protected BusinessObject GetPart(BusinessObject oOccurrence)
Returns a part for the occurrence passed in if it is a PartOccurrence or SmartOccurrence.
8. protected string GetPartNumber(BusinessObject oPart)
Returns a part number for the part passed in.
9. protected string GetTypeString(BusinessObject oNamedItem)
Returns type string for model and catalog items.

56 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Naming Rules

Creating a NameRule Project


1. Create a C# or VB class library project using Visual Studio 2008.
2. Open the class file and change the name of the class provided by the New Project wizard.
[C# example]
public class CommonNameRule
{
}

[VB example]
Public Class CommonNameRule

End Class

3. .NET name rules must derive from NameRuleBase. The base class, NameRuleBase, is
defined with the Ingr.SP3D.Common.Middle namespace in the CommonMiddle.dll
assembly. Add a reference to the CommonMiddle assembly by using Project > Add
Reference… in Visual Studio. CommonMiddle.dll is located in {Product
Path}\Container\Bin\Assemblies\Release folder.
Note: Select the CommonMiddle reference in the Solution Explorer. In Reference
Properties set the Copy Local property value to “False” to avoid copying the reference
assembly to the project’s output folder.
4. Add the following :
[C# example]
using System.Collections.ObjectModel // To access
ReadOnlyCollection<T>.
using Ingr.SP3D.Common.Middle // To access NameRuleBase.

[VB example]
Imports System.Collections.ObjectModel ’ To access
ReadOnlyCollection<T>.
Imports Ingr.SP3D.Common.Middle ’ To access NameRuleBase.

5. Derive the name rule class from NameRuleBase and implement stubs for the abstract
method defined in base class.
[C# example]
public class CommonNameRule : NameRuleBase
{
public override Collection<BusinessObject> GetNamingParents(
BusinessObject
oEntity)
{
// To be implemented

Intergraph Smart™ 3D .NET Programmer’s Guide 57


Creating Naming Rules

throw new Exception("The method or operation is not


implemented.");
}

public override void ComputeName(


BusinessObject oEntity,
ReadOnlyCollection<BusinessObject>
oParents,
BusinessObject oActiveEntity)
{
// To be implemented
throw new Exception("The method or operation is not
implemented.");
}
}

[VB example]
Public Class CommonNameRule
Inherits NameRuleBase

Public Overrides Function GetNamingParents(


ByVal oEntity As BusinessObject
) As Collection(Of BusinessObject)

End Function

Public Overrides Sub ComputeName(


ByVal oEntity As BusinessObject,
ByVal oParents As ReadOnlyCollection(Of
BusinessObject),
ByVal oActiveEntity As BusinessObject)

End Sub
End Class

6. Replace code in the previous override function and method with code for the customized
naming scheme. For details see Writing a Name Rule in the following section.
7. Build your project to produce the name rule assembly, but this name rule assembly must be
made available on the symbol server. For details about assembly location and placement, see
Deployment, which follows Writing a Name Rule.

58 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Naming Rules

Writing a Name Rule


Writing a name rule is all about implementing GetNamingParents and ComputeName.
GetNamingParents allows a name rule implementation to return a set of parents which can be
used to formulate the name. ComputeName allows a name rule implementation to formulate a
name based on a naming scheme, which can include the collection of parents that are passed in.
The base class, NameRuleBase, provides commonly used methods to assist in writing a name
rule.
Design of a name rule requires a naming scheme. The naming scheme can be based on a formula
such as PartName-UniqueCounter or ClassName-UniqueCounter, etc. Based on the naming
scheme of the name rule, decide whether you require parents to formulate the name. If needed,
design how the parents can be obtained.
Following are two examples of name rule implementation:
• Naming scheme: If the object to be named is a part occurrence, the name must be
PartNumber -UniqueCounter. If not, it must be ClassName-UniqueCounter.
As this name rule does not require parents, GetNamingParents implementation will be thin.

[C# Example]
public override Collection<BusinessObject> GetNamingParents(
BusinessObject
oEntity)
{
Collection<BusinessObject> oParents= new
Collection<BusinessObject>();

return oParents;
}

[VB Example]
Public Overrides Function GetNamingParents(
ByVal oEntity As BusinessObject) As Collection(Of
BusinessObject)

GetNamingParents = New Collection(Of BusinessObject)

End Function

To implement ComputeName, you need to determine whether the object to be named is a


part occurrence. This can be done by using the GetPart helper function on the base class.
GetPart returns a part if the object passed in is a part occurrence. Use the GetPartNumber
helper function to get the part number of a part. If the object to be named is not a part
occurrence, use the GetTypeString helper function to get its class name. Use the
GetCountAndLocationID helper method to get a unique counter value for a given name.
To get or set the name of an entity, use the SetName helper method or the GetName helper
function. A name rule needs to set the name only if it has changed. To determine whether the

Intergraph Smart™ 3D .NET Programmer’s Guide 59


Creating Naming Rules

name has changed, compare the formulated name with the name basis from active entity. Use
the GetNamingParentsString helper function to get the name basis.

[C# Example]
public override void ComputeName(
BusinessObject oEntity,
ReadOnlyCollection<BusinessObject>
oParents,
BusinessObject oActiveEntity)
{
string sPartName = "";

// Get part from part occurrence.


BusinessObject oPart = base.GetPart(oEntity);
if (oPart != null)
{
// Get part number from part.
sPartName = base.GetPartNumber(oPart);
}

if (sPartName == "")
{
// Get class name.
sPartName = base.GetTypeString(oEntity);
}

// Remove spaces from name.


char[] cDelimiter = new char[1];
cDelimiter[0] = ' ';
string[] sFields = sPartName.Split(cDelimiter);
sPartName = string.Join("", sFields);

// Get naming parents string from active entity.


string sNameBasis = base.GetNamingParentsString(oActiveEntity);
if (sPartName != sNameBasis)
{
// Set the new "NamingParentsString" on active entity.
base.SetNamingParentsString(oActiveEntity, sPartName);

// Get unique counter value for name string.


long lCount;
string sLocationID = null;
base.GetCountAndLocationID(sPartName, out lCount, out
sLocationID);

// Construct name. Use formatting to display leading zeros for


count.
string sName = sPartName + "-" + lCount.ToString("D4");

// Set name on entity.


base.SetName(oEntity, sName);

60 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Naming Rules

}
}

[VB Example]
Public Overrides Sub ComputeName(
ByVal oObject As BusinessObject, _
ByVal oParents As ReadOnlyCollection(Of
BusinessObject),
ByVal oActiveEntity As BusinessObject)

Dim sPartName As String

' Get part from part occurrence.


Dim oBusinessObject As BusinessObject
oBusinessObject = MyBase.GetPart(oEntity)
If Not oBusinessObject Is Nothing Then
' Get part number from part.
sPartName = MyBase.GetPartNumber(oBusinessObject)
End If

If sPartName.Length() = 0 Then
' Get class name.
sPartName = MyBase.GetTypeString(oEntity)
End If

' Remove spaces from name.


Dim cDelimiter(1) As Char
cDelimiter(0) = " "c
Dim sFields() As String
sFields = sPartName.Split(cDelimiter)
sPartName = String.Join("", sFields)

' Get naming parents string from active entity.


Dim sNameBasis As String
sNameBasis = MyBase.GetNamingParentsString(oActiveEntity)
If Not sNameBasis = sPartName Then
' Set the new "NamingParentsString" on active entity.
MyBase.SetNamingParentsString(oActiveEntity, sPartName)

' Get unique counter value for name string.


Dim lCount As Long
Dim sLocationId As String
lCount = 0
sLocationId = ""
MyBase.GetCountAndLocationID(sPartName, lCount, sLocationId)

' Construct name. Use formatting to display leading zeros for


count.
sPartName = sPartName + "-" + lCount.ToString("D4")

' Set name on entity.

Intergraph Smart™ 3D .NET Programmer’s Guide 61


Creating Naming Rules

MyBase.SetName(oEntity, sPartName)
End If
End Sub

• Naming scheme: If the object to be named is a part occurrence, the name must be
SystemParentName-PartName -UniqueCounter. If not, it must be SystemParentName-
ClassName-UniqueCounter.
This naming scheme uses the name of the system parent; hence implementation of
GetNamingParents must return the system parent of the object being named. Use the
GetParent helper function to get the parent in a particular hierarchy. This function takes an
enumeration value of HierarchyTypes and the child for which the parent must be returned.

[C# Example]
public override Collection<BusinessObject> GetNamingParents(
BusinessObject
oEntity)
{
Collection<BusinessObject> oParents = new
Collection<BusinessObject>();

// Get system parent.


BusinessObject oParentSystem =
base.GetParent(HierarchyTypes.System, oEntity);
if (oParentSystem != null)
{
// Add parent.
oParents.Add(oParentSystem);
}
return oParents;
}

[VB Example]
Public Overrides Function GetNamingParents(
ByVal oEntity As BusinessObject) As Collection(Of
BusinessObject)

GetNamingParents = New Collection(Of BusinessObject)

' Get part from part occurrence.


Dim oParentSystem As BusinessObject
oParentSystem = MyBase. GetParent(HierarchyTypes.System, oEntity)
If Not oParentSystem Is Nothing Then
' Add parent.
GetNamingParents.Add(oParentSystem)
End If

End Function

62 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Naming Rules

ComputeName implementation is very similar to the above example, with the extension that
the naming scheme uses the name of the system parent. Use the GetName function to get the
name of the parent system.

Intergraph Smart™ 3D .NET Programmer’s Guide 63


Creating Naming Rules

Deployment
All customer name rule assemblies must be located in the \NameRules folder beneath \Custom
Symbols, which is a sub-folder of Symbol Share - specified by the “Symbol and custom
program file locations” setting for the Catalog database in Project Management.
{Symbol Share}\Custom Symbols\NameRules\
1. Copy the name rule assembly to the NameRules folder.
2. Update the custom symbol configuration file (CustomSymbolConfig.xml) by running the
Update Custom Symbol Configuration command in the Tools menu of Project
Management.

Configuration
Name rules must be associated with object types before they can be used. This is done by editing
the NamingRules sheet in the GenericNamingRules.xls and updating the database using
bulkload. GenericNamingRules.xls can be found in the {Product
Path}\CatalogData\BulkLoad\DataFiles folder.
Each entry in the NamingRules sheet of the GenericNamingRules.xls file contains four fields:
• Head – the action that needs to be performed when data is bulkloaded. It can be “A” - Add,
“M” - Modify, or “D” – Delete.
• TypeName – Class name to which this name rule applies.
• Name – Display name of the name rule.
• SolverProgID – ProgID of the name rule.
SolverProgID for the name rules authored in .NET must be in the following format:
[AssemblyName],[Namespace].[ClassName]
For example:
Assembly name is CommonNameRuleLib.
Namespace is NameRules.
Class name is CommonNameRule.
The corresponding SolverProgID is:
CommonNameRuleLib,NameRules.CommonNameRule.
An entry in the GenericNamingRules.xls, to add the above to the database looks like this:
Head TypeName Name SolverProgID
A CPDesignEquipment NETNameRule CommonNameRuleLib,NameRules.CommonNameRule

After a successful bulkload operation, the changes to the database can be verified using the
Catalog environment of S3DHost. Expand NamingRules nodes in the Catalog Browser, and
select the object type that was added or modified using bulkload. Verify that SolverProgID has
changed.

64 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Naming Rules

Note: Only new rules should be added to an existing catalog. Using the Delete and Replace
mode or modifying the ProgID of an existing name rule by using the AMD mode is not
supported in this release.

Testing
Start S3DHost.exe and define a workspace to return the object type for which the name rule must
be tested. Select the object in t workspace and display its properties dialog. Change the Name
Rule property value on the object’s properties dialog and apply the change to see the name
modified.

Intergraph Smart™ 3D .NET Programmer’s Guide 65


Programming a Stand-Alone Application

Programming a Stand-Alone Application


Introduction
Besides creating commands that run within the context of the 3D software S3DHost executable,
it is also possible to use the 3D .NET API in a stand-alone program. By stand-alone, it means
that the executable is not part of S3DHost, but independently accesses a 3D software Plant,
including both the Model and Catalog. As stand-alone, the program has access to all the
important 3D software middle tier constructs. Therefore, such a program can deal with objects in
the database as valid 3D objects, and not be forced to deal directly from the underlying relational
database. Furthermore, since all operations on the objects are done within the context of the 3D
Assoc machinery, all manipulations still benefit from the relationships and semantics that exist
for a 3D model. Therefore, the model remains consistent.
Consider the following uses for creating a stand-alone program:
• Make wholesale batch changes to a group of objects in a model database.
• Create a parts list.
• Perform automatic generation of a model (or additions to an existing model).
• Automate project setup (create Catalog, create Model, set up Plant filters, set up
Permission Groups, add users to Permission Groups from Excel, etc.)
• Interface with external tools such as stress analysis software. Extract data from the 3D
software and import into 3rd party software using their API.
• Generally analyze model data, such as number of gate valves, pumps. etc.

Available Tools
When building a stand-alone application, the first thing to keep in mind is that the number of
available services and development components is not as large as that available to the custom
command writer. In particular, none of the client tier level services may be used in a stand-alone
application. These programs are essentially middle tier applications, and as such, do not have
access to the client services. Furthermore, the proper execution of client services depends on
their initialization within the S3DHost executable.

Services Available for Stand-alone Application


Even with this restriction, a powerful set of programming constructs and services exist for the
author of a stand-alone application. These include:
• The MiddleServiceProvider - singleton component that provides access to the other
middle tier services.
• A middle tier version of the TransactionManager - critical managing the committing (or
abortion) of changes made to 3D business objects.

66 Intergraph Smart™ 3D .NET Programmer’s Guide


Programming a Stand-Alone Application

• Site, Plant, Model and Catalog - components that allow you to interrogate, and to some
degree, manipulate these 3D software entities. The caller may open a plant, and then have
access to its model and catalog.
• UOMManager - to convert database units to and from more readable units of measure.
• MetadataManager - provide access to a 3D class, interface, and property definitions.
• BusinessObject – serves as a generic 3D software business object wrapper class that
allows generic access to the properties and relationships for objects that do not yet have
specific 3D .NET wrappers.
• Filters - to filter objects from the database and obtain a collection of business objects,
conforming to a set of filter criteria.
• ErrorLog - a component used to write information to the error log.

Services Not Available for Stand-Alone Applications


The following services and development components exist only in the S3DHost executable, and
cannot be accessed from a stand-alone application.
• GraphicViewMgr
• ValueMgr
• PreferencesMgr
• WorkingSet
• CommandMgr and command classes
• Hiliter
• Locator (graphic locator)
• SelectSet

Writing the Stand-Alone Application


Following assists you through procedures of creating a new 3D .NET stand-alone application.
Besides the standard .NET mechanics of creating a new application, you can learn how to:
• Initialize the 3D .NET machinery
• Connect to a 3D software model database
• Shut down the application so that .NET properly closes.
In almost every case, the .NET stand-alone application is a form-based application. Therefore,
begin by creating a new Windows Forms Application .NET project. In .NET, click File > New
Project…, and then Windows Form Application.

Intergraph Smart™ 3D .NET Programmer’s Guide 67


Programming a Stand-Alone Application

Many of the steps are similar to those for creating a .NET command project. To continue
creating your stand-alone application, see the previous sections Creating a Command Solution
and Project and Writing Commands: Modal Command in the Creating Commands section.
Important: Remember that CommonClient-related services are not valid for stand-alone
applications. You can only add CommonMiddle-related references.
Now, add using statements in the MainForm source. For example, these three statements
provide essentially everything you require in CommonMiddle:
[C# example]
using Ingr.SP3D.Common.Middle.Services;
using Ingr.SP3D.Common.Middle;
using Ingr.SP3D.Common.Exceptions;

[VB example]
Imports Ingr.SP3D.Common.Middle.Services
Imports Ingr.SP3D.Common.Middle
Imports Ingr.SP3D.Common.Middle.Exceptions

Now add code to open a Smart 3D software Model database. There are two approaches to
consider.
1. The simplest mechanism uses a straightforward .NET API to open the most recent Site
that was opened in the 3D software. This should be on the same machine where the
stand-alone application executes. The 3D software leaves information in the Registry that
identifies the last Site that was opened.
2. The second approach allows the code (or the user) to open a specific Site. After the Site
is opened, the code should open a specific Plant and Model or allow the user to specify
what to open. User-interaction is required depending on whether you are writing in
interactive mode or a batch application. The latter may decide what plant or model is
required by some other mechanism (i.e., reading an input file).
The following example takes the simpler approach. To open the most recently accessed site, add
a button to the form and define its Text property “Open Most Recent”. To employ good
programming practices, name the button btnOpenMostRecent.

68 Intergraph Smart™ 3D .NET Programmer’s Guide


Programming a Stand-Alone Application

Double-click the button in the Form Designer window. This displays the code editor for the
button’s Click event handler. Add a class variable for the form to hold the reference to the Site:
[C# example]
public partial class MainForm : Form
{
Site m_oSite = null;

[VB example]
Public Class MainForm
Private m_oSite As Site

In the btnOpenMostRecent Click handler, add code to connect to the most recent site and to
(arbitrarily, for purposes of this example) open the first plant in the list:
[C# example]
private void btnOpenMostRecent_Click(object sender, EventArgs e)
{
// Connect to the Site database found in the Registry.
m_oSite = MiddleServiceProvider.SiteMgr.ConnectSite();
if (m_oSite.Plants.Count > 0)
{
m_oSite.OpenPlant(m_oSite.Plants[0]); // Choose the first.
}
else
{
MessageBox.Show("No plants defined in default Site!");
}
}
[VB example]
Private Sub btnOpenMostRecent_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnOpenMostRecent.Click
' Connect to the Site database found in the Registry.
m_oSite = MiddleServiceProvider.SiteMgr.ConnectSite()
If (m_oSite.Plants.Count > 0) Then
m_oSite.OpenPlant(m_oSite.Plants(0)) 'Choose the first.
Else
MessageBox.Show("No plants defined in default Site!")
End If
End Sub

The application is now ready to begin processing data in the model. The simple act of connecting
a site performs all the necessary 3D .NET initialization.
When shutting down the stand-alone application, it is necessary to do some clean-up in order to
release resources. Generally, this consists of aborting any potentially ongoing database
transactions, and invoking the MiddleServiceProvider Cleanup method. The best place to do
this is in the main form’s FormClosing event handler:

Intergraph Smart™ 3D .NET Programmer’s Guide 69


Programming a Stand-Alone Application

[C# example]
private void MainForm_FormClosing(object sender, FormClosingEventArgs
e)
{
MiddleServiceProvider.TransactionMgr.Abort();
MiddleServiceProvider.Cleanup();
}
[VB example]
Private void SAMain_FormClosing(object sender, FormClosingEventArgs e)
{
MiddleServiceProvider.TransactionMgr.Abort();
MiddleServiceProvider.Cleanup();
}

SAPBase Example Projects


Delivered with the examples are two projects that provide a basic shell from which to develop a
stand-alone application. These are called SAPBase. A C# language version is located as follows:
{Product Path}\CommonApp\SOM\Examples\SAPBase, and the VB version is: {Product
Path}\CommonApp\SOM\Examples\SAPBaseVB.
These example projects provide forms for opening a site and plant, and also code to properly
shut down the application, as described previously. To use them, it is best that you copy the
project from the language folder of your choice to a target folder. Then rename the project file
(SAPBase.vbproj for the VB version or SAPBase.csproj for the C# version) to a more descriptive
name.
Important: Due to the fact that example .NET projects contain references that were established
on a computer where they were created, and for which the paths are likely different from those
on your development computer, you must re-reference CommonMiddle in order to build the
copied project. You also need to consider references to other assemblies that your program may
require such as, EquipmentMiddle, SpaceMiddle, etc.

A Real World Example: PartSubImpact


Included in the example code is the PartSubImpact project. This is a complete working example,
not just a template. Review the project to see examples of Filter use and BusinessObject
manipulations.
The PartSubImpact project can be found in the following location: {Product
Path}\CommonApp\SOM\Examples\PartSubImpact.

Runtime and Build Considerations


Because 3D .NET software executes against underlying 32 bit COM machinery, it is necessary to
build executables that use the 3D .NET in strict 32 bit mode. The SAPBase projects are delivered
with those settings. To set it for stand-alone applications that do not use SAPBase, see the
following discussions for settings.

70 Intergraph Smart™ 3D .NET Programmer’s Guide


Programming a Stand-Alone Application

Settings for a C# Project


On the .NET Project menu, click <ProjectName> Properties…. Click Build and for the
Platform target:, and make sure “x86” is selected.

Intergraph Smart™ 3D .NET Programmer’s Guide 71


Programming a Stand-Alone Application

Settings for VB Project


On the .NET Project menu, click <ProjectName> Properties…. Click Compile, and for the
Target CPU:, make sure that “x86” is selected.

Runtime Considerations
In order for the stand-alone application to execute properly, the system PATH variable must be
set to contain paths to {Product Path}\Smart3D\Core\Runtime and to {Product
Path}\Smart3D\GeometryTopology\Runtime.
To make any changes, select Start > Control Panel > System > Advanced > Environment
Variables.

72 Intergraph Smart™ 3D .NET Programmer’s Guide


Localization

Localization
Introduction
When creating a user interface or conveying a message to the user we need to be aware of our
audience. Localization in this sense is preparing the project to allow for easy modification of
messages and user interfaces to be translated into different languages and/or locales.
For example:
throw new InvalidParentSystemException("The parent system is not in
working status.");

The assumption with this example is that English is the audience language and therefore no
localization is needed. However, if the project is later to be used in other parts of the world with
different languages and/or locales; how do we translate these types of messages? The answer is,
Recompilation. In that case we would need to translate all messages to each particular world
market and recompile. This clearly is not a feasible solution.
To make localization simpler and more robust, we use separate resource files. These files are
used by the message authors to translate the messages to their specific locale. After the
translation is complete, just generate the resource .dll file that contains the current locale. This
way there is no need to change and recompile the project, and only the language and/or locale are
affected.
To correctly achieve the separation of project and locale resources, just follow a series of steps,
to guide you through the recommended process of project localization.

Adding a Resource File


The resource file includes the resource ID and the string for the applicable locale. This file is
used to generate a .dll that serves as the localizer. Following is an example of the earlier message
contained in the resource file. Notice that ID ‘1’ corresponds to the string.

1. In the Solution Explorer of Visual Studio, right-click on the project name.


2. Select Add and then select New Item….

Intergraph Smart™ 3D .NET Programmer’s Guide 73


Localization

3. Select Resource File from the list in the Templates section.


4. Enter a name in the Name text box; for example, MyAppResourceMiddle.

5. Right-click on the newly created resource file in the Solution Explorer.


6. Then, right-click on MyAppResourceMiddle.resx.
7. On the context menu popup, click Exclude From Project. You will create your own
localizer .dll. This is so localization can be updated without recompiling the project.

74 Intergraph Smart™ 3D .NET Programmer’s Guide


Localization

8. Now find your project location and add a locale folder; for example,
D:\Users\MyAppMiddle.
9. Add an en-US folder for the United States English locale. Customize this step to set the
appropriate locale.

10. Move the resource file (MyAppResourceMiddle.Designer.cs) to the en-US folder and
delete the original Designer.cs file.

Creating Batch File to Build Resource DLL


1. Create a batch file that uses the resgen tool, which is The Resource File Generator for
converting resource format (.resx) files to common language runtime binary (.resources)
files, which can be compiled into satellite assemblies. This batch file can be directly
executed to generate the locale specific .dll file or can also be added to a post-build step
in your project. Since this example is building an English United States locale, we use the
en-US folder created earlier.
2. Create a new .bat file in the en-US folder.
3. Add the name Build to the beginning of the file name; for example,
BuildMyAppMiddleResource.bat.
4. Open the file with an editor, such as Notepad.
5. Copy and paste the following script into the file, and save it.

REM compile and create the .NET resource file

Intergraph Smart™ 3D .NET Programmer’s Guide 75


Localization

SETLOCAL

Rem *** Required for ResGen.exe and AL.exe ***


call "%VS100COMNTOOLS%vsvars32.bat"

Rem *** Set paths for ResGen.exe and AL.exe ***


set resgpath=%WindowsSdkDir%bin\NETFX 4.0 Tools\
set alpath=%WindowsSdkDir%bin\NETFX 4.0 Tools\

"%resgpath%resgen.exe" <MyAppDirectory>\en-US\MyAppResource.Resx
<MyAppDirectory>\en-US\MyAppResource.resources

"%alpath%al.exe" /embed:<MyAppDirectory>\en-
US\MyAppResource.resources,MyAppResource.resources /out:<MyAppDirectory>\en-
US\MyAppResource.resources.dll /c:en-US

ENDLOCAL

6. Modify the project location <MyAppDirectory> to the location of your project. After
correcting the project location, modify the resource file names.
7. Save and run the batch file. This creates the necessary files for .NET to use the resources
for your specific locale. At this point the localized .dll file can be used. The
CommonMiddle API provides a static class, CmnLocalizer, which resolves and returns
the localized string based on the resource .dll and the executing assembly.
8. Add the CommonMiddle reference to your project - {Product
Path}\Container\Bin\Assemblies\Debug\CommonMiddle.dll. Now, the localizer class can
be called on your code.
string localizedString = CmnLocalizer.GetString(resourceId,
defaultMessage,"MyAppResourceMiddle",
"MyAppMiddle");

Notice the hard-coded strings. It could be a bit tedious and unproductive to hard-code the
resource name and assembly name every time when localizing strings.
9. Add two more classes - a resource identifier and a localizer class, which saves time for
future work.
The resource identifier class contains all of the constants that identify each particular resource
string, and the localizer class provides a convenient API in which to get a localized string from
the resource .dll.

76 Intergraph Smart™ 3D .NET Programmer’s Guide


Localization

Adding Resource Identifier Class


1. Add a new class to the project and name it appropriately. For this example it is
MyAppResourceIdentifier. The int constant in the resource identifier corresponds to the
ID number on the resource file. Notice that the int constant is assigned the value ‘1’,
which corresponds to our example resource string from the earlier discussion.

2. Modify the resource identifier class to be public and static. Also, change the
namespace to an appropriate namespace, and add a DefaultResource and
DefaultAssembly string constants. The DefaultResource constant is the name of
your resource file, MyAppResourceMiddle. The DefaultAssembly constant is the
name of the project output assembly, MyAppMiddle.

Adding Localizer Class


The localizer class delegates the call to the CmnLocalizer class internally, which handles
retrieving the correct message based on the inputs.
1. After adding a new localizer class, MyAppLocalizer, open the class and change the
class to static.
2. Add a public method with ID as int and string for a default message.

Intergraph Smart™ 3D .NET Programmer’s Guide 77


Localization

Now, you can use the localizer to get the localized string by simply specifying the resource
identifier and default string.
string localizedMessage = MyAppLocalizer.GetString(
MyAppResourceIdentifier.ErrInvalidApprovalStatusP
arentSystem,
"The parent system is not in working status.");

throw new InvalidParentSystemException(localizedMessage);

78 Intergraph Smart™ 3D .NET Programmer’s Guide


Custom Folders for User Assemblies

Custom Folders for User Assemblies


Often users need to reference custom assemblies defined outside of the software folder structure.
These assemblies can be:

• Shared Content Assemblies


o COM-visible .NET wrappers to delegate calls from VB6 (COM) content to .NET
content.
o .NET Assemblies that provide common .NET content services.
• Client Assemblies
o Commands and custom programs developed by a user for client applications.

The software needs to know the location of these assemblies in order to resolve and load them
during runtime. To define the location of custom assemblies, you can:
1. Locate the S3DCustomAssemblyPath.xml in the XML folder in your SymbolShare
folder. If it does not exist, create a new XML file with this name.
2. The XML file can have two elements: CustomMiddleServicesPath and
CustomClientServicesPath. You can edit and add your own path to each element, but
each element can consist of only one path.
Sample XML file:

<?xml version="1.0" encoding="utf-8" ?>


<S3DCustomAssemblyPath>

<CustomMiddleServicesPath>C:\Temp\Debug</CustomMiddleServicesPath
>
<CustomClientServicesPath />
</S3DCustomAssemblyPath>

3. If the XML file is found and there is a valid directory entry in one or both of the expected
elements in the XML, then the assembly resolver tries to load the assembly based on the
retrieved paths.

Intergraph Smart™ 3D .NET Programmer’s Guide 79


Security Issues when Deploying Assemblies on a Shared Network

Security Issues when Deploying


Assemblies on a Shared Network
Windows security allows you to secure resources according to user roles. For example, an
Administrator has unrestricted permissions, but a Guest has very restricted access.
The .NET Framework includes a security mechanism called Code Access Security, which helps
you to further secure your application. Using Code Access Security, a variety of permissions are
applied depending on where the code originated, identified by the zone of the assembly, and the
permissions identified for that zone in the Code Access Security policy. For example, code that
exists on a machine is identified as being located in the My Computer zone. Code that is
downloaded from another machine on the local intranet is identified as being located in the Local
Intranet zone.
Smart 3D uses symbols, name rules, custom commands, etc., from DLLs in the SymbolShare,
which is usually a UNC location. In previous versions using .NET framework v3.5, a specific
procedure was required (referred to as the CASPOL.exe procedure) to enable trust to UNC
locations containing DLLs used by the Smart 3D processes.

.NET Framework 4.0


An easier method is provided with .NET Framework 4.0 (Smart 3D v2014 and v2014 R1) to
enable trust on Assemblies loaded from remote locations (i.e., from UNC paths and not from
local disk). This is achieved by adding following setting to the application.exe.config file:
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
</startup>
<runtime>
<loadFromRemoteSources enabled="true" />
</runtime>
</configuration>

.NET Framework 4.5.2


To enable trust on Assemblies loaded from remote locations with .NET Framework 4.5.2 (Smart
3D v2016), this is achieved by adding following setting to the application.exe.config file:
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.5.2" sku=".NETFramework,Version=v4.5.2" />
</startup>
<runtime>
<loadFromRemoteSources enabled="true" />
</runtime>

80 Intergraph Smart™ 3D .NET Programmer’s Guide


Security Issues when Deploying Assemblies on a Shared Network

</configuration>
Smart 3D executables, according to the software version installed on your computer, already
contain these required entries in the config file to permit trusting and loading Assemblies from
remote locations. When you use Smart 3D’s .NET API to write your own custom executables,
ensure that you add the configuration file for setting your custom executable’s
<appname>.exe.config file to allow it to trust assemblies loaded from remote sources.

Intergraph Smart™ 3D .NET Programmer’s Guide 81


Creating .NET Symbols

Creating .NET Symbols


Creating Smart 3D symbol content using the .NET 3D API provides the following benefits:
• Access to the new and improved 3D API application objects and services.
• Use of the 3D API from within the latest .NET framework.
• Built-in support for running in future 64-bit applications.
To place a symbol in the 3D environment, you need graphical data (.NET symbol) and non-
graphical data (Excel workbook containing specifications, rules, dimensional data, etc.).
To create a symbol in the software, you need to perform the following:
• Understand the geometry and use of the symbol.
• Write .NET code for the geometry outputs to be created.
• Bulkload the symbol data into the catalog database.
The following sections use a ball valve for discussion in creating a symbol.

82 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols

Understanding the Geometry


Before preparing a symbol, study the symbol in terms of the dimensional parameters required to
uniquely define the symbol, the ports or connect points required for the symbol, how the
geometry of the symbol will be represented graphically, the origin of the symbol, the orientation
of the symbol, and so forth.
Determine the various aspects of the symbol to be drawn such as Physical, Insulation,
Maintenance, and so forth. This means that you should decide whether to simply draw the
symbol’s physical representation or whether to add the insulation graphics, maintenance space
required, and so forth.
Referring to the example of a ball valve, Physical and Insulation aspects of the valve are drawn.
Geometric Representation: The valve is drawn with a circular flange on the left hand side as a
cylinder; next a cylinder, a sphere, a cylinder at the center, and another circular flange at the
right-hand side. This means three outputs are drawn to represent the Physical Aspect of the valve
(Port1, ValveBody, and Port2). Please note that even though this example appears to represent a
flanged ball valve, the code is generic enough to accommodate different end preparations such as
welded, flanged, threaded, and so forth. You can define a more complex geometric
representation of the symbol as you want.

Dimensions: As a symmetrical valve, the face to face dimension is required in order to draw the
valve. The dimensions required to draw the flange are obtained from the standard geometric data
bulkloaded in the Smart 3D project’s catalog database. This data is available in the
AllCommon.xls for the various end preparations (Bolted, Male, or Female). The radius of the
sphere is assumed to be a factor of the known dimensions. Hence the input parameters required
those for representing the Physical Aspect (Face to Face dimension).
Orientation: The symbol is drawn with the origin (0, 0, 0) at the center of the valve. The left-
hand side port is drawn along –X direction and the right-hand side port is drawn along +X
direction.

Intergraph Smart™ 3D .NET Programmer’s Guide 83


Creating .NET Symbols

Defining Ports on Symbols


Most symbols consist of at least one port, which is a point on a part that connects to a routed
item, such as pipe or cableway. A port consists of an attachment point and direction, set of
application properties, and physical geometry depiction. A different class of port is required for
each type of routing item. For example, piping requires one type of port, while cableway requires
another.
You define ports when you create a symbol and define the geometry of a part. In .NET, a
function specifies the port type, name, attachment point, and attachment vector. The software
places the ports based on the information in the geometry definition file for the part and the
reference data for the part. The geometry definition file defines the port type, name, attachment
point, and attachment vector. The reference data for the specific part (item of the part class)
defines the remainder of the property values for the port.

84 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols

Writing Code for the .NET Symbol


The Smart 3D software consists of the following geometry APIs, through which the outputs need
to be generated.
• Line3D
• Circle3D
• Arc3D
• ComplexString3D
• Projection3D
• Revolution3D
• Torus3D
• BSplineCurve3D
• Cone3D
• Nozzle
The SymbolGeometryHelper class contains functionality for primitive shapes such as
CreateCylinder, CreateCone, CreateCircularTorus, CreateSphere, etc., which are used for
creating different outputs. You can find this helper with CommonMiddle services.

Assembly Creation
First, decide which assembly will contain the new symbol. To avoid performance issues when
loading multiple assemblies, group .NET symbols according to BusinessObject type and usage
type.
Build the assembly to %OLE_SERVER%\Custom Symbols. You can build the assembly in any
subfolder under the Custom Symbols folder.

Deploying the Symbols


Under Project Management, select the Catalog and then run “Update Custom Symbol
Configuration” on the Tools menu. This updates “CustomSymbolConfig.xml” with the ProgID
of the new assembly and its location relative to the “%OLE_SERVER%” path.

Naming of the Symbol Definition


The definition name of a symbol should be unique in the database. The namespace of symbol
definition class should be specified as follows:

Intergraph Smart™ 3D .NET Programmer’s Guide 85


Creating .NET Symbols

<CompanyName>.SP3D.Content.<Specialization>. e.g., Ingr.SP3D.Content.Structure

Also recommended, if a delivered symbol definition must be changed to meet a specific


requirement, change its namespace and symbol definition class name so that the identity of the
modified symbol is different (unique) from the one delivered in the software.

Creating Custom To Do List Messages


During computation of the symbol, there are situations where a To Do List message needs to be
created for the symbol business object so that a user can be notified and the problem can be
corrected. It is important that the information on a To Do List message is specific to the problem
and assists the user with diagnosis and correction. Smart 3D software allows a content writer to
decide when to create the To Do List message and to customize its type and message through
ToDoListMessage constructors.
Normally, a ToDoMessageError type should be used when the computation cannot proceed
further.
'Following code creates an error ToDoListMessage.
Dim myToDoListMessage As ToDoListMessage = New
ToDoListMessage(ToDoMessageTypes.ToDoMessageError,
MyLocalizer.GetString(ResourceIds.SymbolError, "Something wrong in my
symbol. This is an error."))

A ToDoMessageWarning type should be used when the custom definition code did not return
expected results, which might need action by the user, but is still able to complete computation.

'Following code creates a warning ToDoListMessage.


Dim myToDoListMessage As ToDoListMessage = New
ToDoListMessage(ToDoMessageTypes.ToDoMessageWarning,
MyLocalizer.GetString(ResourceIds.SymbolWarning, "Something wrong in my
symbol. This is a warning."))

Also, a content writer has the option to save resource identifier information by providing the
module name that contains the resource table and the ID of the resource string itself.
'Following code creates an error ToDoListMessage with a localizable
message.
Dim myToDoListMessage As ToDoListMessage = New
ToDoListMessage(ToDoMessageTypes.ToDoMessageError, “MyResourceModuleName”,
int messageID, "Something wrong in my symbol."))

Default software behavior is to show the symbol business object as the “object to update” on the
ToDoListMessage. A content writer has the option to add another business object as the “object
to update”, by specifying it as an argument.

86 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols

'Following code creates an error ToDoListMessage with another object to


update.
Dim myToDoListMessage As ToDoListMessage = New
ToDoListMessage(ToDoMessageTypes.ToDoMessageError, “MyResourceModuleName”,
int messageID, "Something wrong in my symbol but another object needs to
be updated.", objectToUpdate)

When a To Do List message is created, it must be set on the base class to allow the software to
be able to use it. If an error ToDoListMessage is created, computation can be stopped.

'Following code sets the ToDoListMessage on the base class.


MyBase.ToDoListMessage = myToDoListMessage
'Stop computation as it is an error.
Return

Intergraph Smart™ 3D .NET Programmer’s Guide 87


Creating .NET Symbols

Bulkloading the Symbol


You should find an existing symbol similar in geometry to your custom symbol, nozzle location,
and orientation, etc., and use its bulkload datasheet as a base in which to prepare a datasheet to
bulkload the new symbol.
For example, to bulkload inline valves with two nozzles use the ‘BALR’ worksheet in the
Piping.xls sheet. To bulkload an inline symbol when there is a change in diameter ‘REDC’, use
the Piping.xls worksheet. You can have as many attributes as occurrence attributes (property
values that can be changed at runtime), but this should be specified in the same row where the
SymbolDefinition is mentioned.
A new symbol’s non-graphic data should be added in a specified Excel workbook. For example,
Piping.xls should be edited for a new Piping symbol. Equipment.xls should be edited for a new
Equipment symbol. Each of these Excel books defines the classes, parts, specifications, rules,
and so forth. Some common workbooks, such as, AllCommon.xls and AllCodeLists.xls also
`may need to be edited.
For each unique symbol, a separate worksheet should be added to the Excel workbook with
appropriate detail. You can use the Excel workbook generated by the Part Definition Symbol
Wizard. Provide nozzle information in the part class Excel sheet depending on the number of
nozzles in the newly created symbol. Use ‘A’ to append, ‘M’ to modify, and ‘D’ to delete data
into the Catalog database when bulkloading in Append mode.

Bulkloading the Piping Symbol


See the spreadsheets that are created for the ball valve delivered on your computer:
{Product Path}\CatalogData\BulkLoad\DotNetSampleDataFiles\Piping-DotNet.xls
{Product Path}\CatalogData\BulkLoad\DotNetSampleDataFiles\PipingSpecification-DotNet.xls
For more information not covered in this programming guide, including guidelines on
bulkloading symbols, see ”Loading Reference Data into the Catalog” in the Reference Data
Guide.

88 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols

Placing the Symbol


Complete the following steps for placing a piping symbol:
1. Open the Smart 3D software and navigate to the Piping task.
2. Click Route Pipe.
3. Select the run starting point.
If you select a feature located at the end of an existing run, the software continues the run
of the selected feature. If you select an equipment nozzle, a point in space, or a point
along a straight feature, the software prompts you to create a new pipe run.
4. On the New Pipe Run dialog box, type a name for the pipe run. If you do not enter a
name, the software automatically generates a name. Select the Piping System
(Specification IC0031, IC0032, N0, N1) and NPD to be used for placing the pipeline.
The NPD and Specification should be the same you used in the bulkload data for the
symbol.
5. Click OK to close the New Pipe Run dialog box.
6. Select point-to-end routing of your pipe run.
7. Click Insert Component to insert a component.
The Insert Component command adds valves, strainers, laterals, and other components
to a pipe run. You can add components either during the routing of a pipe run or after the
pipe has been routed.
The software uses the pipe specification, nominal diameter of the selected pipe run, and
the geometry of the insertion point to filter the available components. For example, if the
insertion point is not at the end of a pipe run or at an equipment nozzle, turn components
are not included in the list of available components. When you insert a component, the
software generates any mating and connection parts required to connect the inserted part
to the adjacent objects.
When inserting components, you can use the Tools > Pinpoint and Tools > Point Along
commands to position components precisely in a pipe run.
8. Select the component type and option in the Type and Option boxes.
9. Click to define the position of the component if you are placing it in a straight feature.
If needed, change the position of the component using Flip, Reference Position, and
Angle options.
10. Click Finish.
11. You can check the properties (input parameter values) by selecting the component and
then click Properties.

Intergraph Smart™ 3D .NET Programmer’s Guide 89


Creating .NET Symbols

Creating an Advanced Symbol


Some symbols often use more advanced techniques in order to meet the different set of
requirements for them.

Dynamic Outputs
Often the symbol outputs are not known before-hand and are determined dynamically during the
computation of the symbol. For example, concerning a symbol to create the geometry of a stair,
the number of outputs is dependent on the span of the stair and pitch.
The 3D API framework allows addition of these outputs dynamically. To add dynamic outputs to
the symbol:
1. Inform symbol machinery that you will be creating variable outputs.
If you derive your symbol definition class from a Business Object-specific base class
(e.g., StairSymbolDefinition), this step is not required, and you can jump directly to step
2.
Add VariableOutputs attribute to your class.
<VariableOutputs()>

2. Construct the output object.Symbol output must be persistent; i.e., it must be created with
a valid database connection.
3. Add an output object to the symbol outputs with a unique name.
'Add an output object myOutputObject named “MyOutputName”
'to the aspect m_oSimplePhysicalAspect.

m_oSimplePhysicalAspect.Outputs.Add("MyOutputName ", myOutputObject)

Custom Weight and Center of Gravity (COG)


If a symbol is responsible for computing weight and center of gravity (COG), the symbol should
compute the volume and COG of the geometric outputs in the ConstructOutputs module. This
results in better performance rather than returning the outputs later and performing calculation.
Catalog parts can have single or multiple materials. For example, a pipe part has single material,
but a ladder can have a variety of materials for the frame, cage, safety gate, support legs, bolts
etc. Weight and COG evaluation for the parts need to consider all the individual materials.
The 3D API framework supports custom weight COG calculation for both kinds of parts.
Evaluating weight COG in the symbol consists of:

1. Get the net volume and COG for the geometric outputs of the symbol for each material.

90 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols

2. Construct a VolumeCOG named output object for each material and add it as output to
the symbol.

'Create a VolumeCOG object for a HandRail symbol.


oHandRailVolCOG = New VolumeCG(oConnection, dTotalVolume, dCOGX,
dCOGY, dCOGZ)

m_oSimplePhysicalAspect.Outputs[“VolumeCOG”] = oHandRailVolCOG

3. Symbols which handle parts with single material only need to complete previous steps 1
and 2. Weight COG will be calculated by the business object from this named output.

4. Symbols which handle parts with multiple materials need to realize ICustomWeightCG.
This interface provides methods to evaluate weight COG or the part by the symbol. In
this case, the symbol gets the outputs from the output collection and the materials from
the part to calculate the net weight COG.

EvaluateWeightCG(ByVal oBO As BusinessObject) Implements


ICustomWeightCG.EvaluateWeightCG

'Get VolumeCOG output.


'Get the output from the symbol output collection using the
'helper method provided on SymbolHelper.
oObject = SymbolHelper.GetSymbolOutput(oBO, "SimplePhysical", _
"VolumeCOG")
If Not oObject Is Nothing Then
oHandRailVolCOG = DirectCast(oObject, VolumeCG)
dVolume = oHandRailVolCOG.Volume
dCOGX = oHandRailVolCOG.COGX
dCOGY = oHandRailVolCOG.COGY
dCOGZ = oHandRailVolCOG.COGZ

'Evaluate weight from output volume and the material


'properties on the given user interface.
dWeight = EvaluateWeightFromVolume(oBO, dVolume, _
sIJUAHandRailTypeAProps)

'Set the net weight and COG on the Business Object using
'helper method provided on StructureSymbolDefinition.
SymbolHelper.SetWeightAndCOG(oBO, dWeight, dCOGX, dCOGY, dCOGZ)

End If

Custom Evaluation of Origin and Orientation


Often parts need to be positioned and oriented correctly based on the given inputs. For example,
a stair needs to be positioned and oriented based on the TopSupport, SideReference, and
BottomSupport inputs selected by the user.
The 3D API framework provides an interface ICustomEvaluate, which should be realized by
the symbol to support evaluation of origin and orientation for parts.

Intergraph Smart™ 3D .NET Programmer’s Guide 91


Creating .NET Symbols

Evaluating origin and orientation of a part involves the following steps:


1. Realize ICustomEvaluate on the symbol.
2. Construct the transformation matrix based on the given inputs.
The following code demonstrates how to construct the transformation matrix from the vectors
based on the geometric inputs and the position value given for a stair:

EvaluateGeometry(ByVal oBO As BusinessObject, bPartChanged As bool,


bGeomInputChanged As bool, bPropertyValueChanged As bool)


'Initialize the matrix to identity.
oMatrix = New Matrix4X4()
'Construct a double array and set the actual double values for the local
'x, y, z vectors in the transformation matrix.
'Also set the translation component.
Dim dArrMatrix As Double() = New Double(15) {}

'Set the double array on the matrix.


oMatrix.Set(dArrMatrix)

3. Set the transformation matrix on the Business Object.


The following code shows how to set the transformation matrix on the Ladder object.

'Set the orientation matrix on the ladder or stair.


Dim ladderStairObject As StairLadderBase = DirectCast(oBO,
StairLadderBase)
ladderStairObject.Matrix = oMatrixOrientation

Custom Foul Check


Some business objects delegate foul check to the symbol, which allows the symbol writer to
override the default implementation. For example, a footing assembly symbol may need to return
all the supported member part(s) as connected parts to suppress interference between them and
the footing. A footing component symbol may need to return non-participant for interference
check to avoid duplicate interference reporting by the components.
The 3D API framework provides an interface ICustomFoulCheck,which should be realized by
the symbol to support custom behavior of foul check for parts.
Supporting custom behavior for foul check on a symbol involves the following:
1. Realize ICustomFoulCheck on the symbol.
2. GetConnectedParts should return the collection of connected parts or return null.
3. GetInterferenceType should return the interference type.

92 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols

The following code example shows how to implement GetConnectedParts and


GetInterferenceType for the footing assembly symbol:

GetConnectedParts(ByVal oBO As BusinessObject) As ReadOnlyCollection(Of


BusinessObject)

'Get all the supported objects from the footing.
Dim oConnectedPartsList As New List(Of BusinessObject)()

'Get all the supported objects from the footing.
'For each supported object, if it is a MemberSystem, get its parts and
add them to the list.

Return New ReadOnlyCollection(Of BusinessObject)(oConnectedPartsList)


End Function

GetFoulInterfaceType(ByVal oBO As BusinessObject) As FoulInterfaceType


'Footing assembly is participant in interference.
Return FoulInterfaceType.Participant
End Function

Custom Mirror
Some business objects delegate the mirror implementation for the symbol code, which allows the
symbol writer to override the mirror behavior of a specific part; e.g., a stair may need to be
flipped around the top support on mirror.
The 3D API framework provides an interface ICustomMirror, which should be realized by the
symbol to support custom mirror behavior for mirroring parts.
Supporting custom behavior for mirror on a symbol involves the following:
1. Realize ICustomMirror on the symbol.
2. Set properties that effect mirror behavior inside the Mirror method.
The following code shows how to implement mirror for a ladder:

Mirror(ByVal oBusinessObject As BusinessObject, ByVal oBusinessObjectOrig As


BusinessObject, ByVal oMirrorPlane As IPlane, ByVal oTransformMatrix As
Matrix4X4, ByVal bIsCopy As Boolean)

'Add custom behavior for mirror here based on mirror behavior.

Dim iMirrorBevahior As Integer =


CInt(SymbolHelper.GetLongProperty(DirectCast(oPart, BusinessObject),
SPSSymbolConstants.IPART, SPSSymbolConstants.MIRRORBEHAVIOROPTION))
If iMirrorBevahior = SPSSymbolConstants.REPLACEMENTPARTVALUE Then

Intergraph Smart™ 3D .NET Programmer’s Guide 93


Creating .NET Symbols

Custom Property Management


Client tier code for some business objects may use the symbol code to verify the validity of
values given for properties on placement and during edit through the property pages. For
example, a stair can only support angle values within a certain range. Also, a ladder symbol that
only supports a vertical ladder may need to have the angle field read-only only in the client tier.
The 3D API framework provides an interface ICustomPropertyManagement, which should be
realized by the symbol to support validation and management of the properties on the part.
Implementation of custom property management involves the following:
1. Realize ICustomPropertyManagement on the symbol.
2. OnPreLoad is called immediately before the properties are loaded in the property page
control. Any change to the display status of properties can be done here.

Following code demonstrates how to set the display status of a property to read-only:

OnPreLoad(ByVal oBusinessObject As BusinessObject, ByVal


CollAllDisplayedValues As ReadOnlyCollection(Of PropertyDescriptor))

'Validate each property value.

For i As Integer = 0 To CollAllDisplayedValues.Count - 1


Dim oPropDescr As PropertyDescriptor = CollAllDisplayedValues(i)
Dim oPropValue As PropertyValue = oPropDescr.[Property]
Dim sPropName As String = oPropValue.PropertyInfo.Name

'Make all these properties read-only.


Select Case sPropName
Case "MyReadOnlyPropertyName"
oPropDescr.[ReadOnly] = True
Exit Select
End Select

Next

3. OnPropertyChange is called each time a property is modified. Any custom validation


can be done here.

Following code shows how to validate the value of a property on change in the property value.

OnPropertyChange(ByVal oBusinessObject As BusinessObject, ByVal


CollAllDisplayedValues As ReadOnlyCollection(Of PropertyDescriptor), ByVal
oPropToChange As PropertyDescriptor, ByVal oNewPropValue As PropertyValue,
ByRef sErrorMessage As String) As Boolean

sInterfaceName = oPropToChange.[Property].PropertyInfo.InterfaceInfo.Name
sPropertyName = oPropToChange.[Property].PropertyInfo.Name

94 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols


'Check the property value.
If sErrorMessage.Length > 0 Then
bOnPreLoad = False
Exit For
End If

Intergraph Smart™ 3D .NET Programmer’s Guide 95


Creating .NET Symbols

Creating .NET symbols using the Symbol Wizard


Deployment
To help you create new symbols, the Symbol Wizard is delivered with the software. The wizard
is an executable, runs as a stand-alone application, and is delivered as follows:

{Product Path}\Core\Container\Bin\Assemblies\Release\SymbolWizard.exe
For more information see its accompanying context sensitive (F1) help.

The wizard implementation is language neutral. It uses style sheet templates and XML
transformation to generate a .NET symbol definition for any programming language desired by
the symbol author. The style sheet templates are delivered in separate folders, \CS and \VB:
{Product Path}\CommonApp\SOM\Client\Services\SymbolWizard\Templates

One style sheet for each VB or C# solution, project, assembly information, XML aspects, and the
Symbol class is delivered, but these can be replaced with other programming language templates.

Workflow
The workflow for using the wizard to create a new symbol consists of the following steps:
1. Identify the .NET symbol project and location.
2. Specify either a new or existing project in which to add the .NET symbol.
3. Provide a mamespace and the symbol class name. Define inputs to the symbol in the
inputs grid. For naming guidelines, see the previous section Naming of the Symbol
Definition in Writing Code for the .NET Symbol.
4. Select aspects defined by the symbol.
5. Define outputs for each aspect.

Ending the wizard with finish, the new .NET Symbol class is created in the target project.

Application-specific Symbol Definition Base Classes


By default, the symbol class created by the wizard inherits from CustomSymbolDefinition. The
software provides application and Business Object-specific symbol definition base classes that
provide some useful functionality, for example, StructureSymbolDefinition,
LadderSymbolDefinition, HandRailSymbolDefinition, and more. A symbol should inherit
from one of these base classes to provide implementation for all the necessary behavior on the
symbol. For more information, see Marine and Plant structure symbol API.

The SymbolGeometryHelper, functionality available in the CommonMiddle API, provides


useful API to create geometry primitives for symbol output. Some of these functions include:
CreateCylinder(), CreateCone(), CreateCircularTorus(), and more.

96 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols

Migrating an Existing Symbol to .NET


Consider the following before migrating existing COM content to .NET:
1. Do I have access to VB6, VC++, or Visual Studio 2013 for developing?
2. Does the symbol need to run in a 64 bit version of the application yet?
3. Are there features of .NET or the new 3D API in which I should take advantage?
If you answer yes to some or all of the above, then consider migrating the symbol to .NET. See
the next section for guidelines on migration.

Using the Symbol Wizard for Migration


The Symbol Wizard provides symbol authors the ability to create new symbols or to migrate
specific symbol definitions to .NET.
1. Identify the .NET symbol project and location.
a. Specify either a new project for the .NET symbol to be created or to add the symbol to an
existing project.
2. Provide a namespace and the new symbol class name. See the section Naming of the Symbol
Definition in Writing Code for the .NET Symbol for naming guidelines.

3. Identify the existing symbol(s) to be migrated.


a. Select a .dll that contains existing symbols.
b. Select one or more required existing symbols from the list of available symbols.
On finish, the new .NET Symbol class is added to the new or existing project.

Migrated .NET Symbol Class


The migrated .NET Symbol class inherits the following information from the old symbol:

• Inputs, Aspects, and Outputs

• A new symbol definition format of the ConstructOutputs() method stub is provided for
logic to be added to create the necessary outputs for each aspect.

Intergraph Smart™ 3D .NET Programmer’s Guide 97


Creating .NET Symbols

Creating a Custom Assembly


Custom Assembly represents an extension of a 3D symbol where more than geometry can be
produced as outputs. You can include other first class business objects, such as nozzles on
equipment or structural members in an equipment foundation. The Custom Assembly inherits
from the base symbol definition class so the same deployment and advanced extensions exist for
the Custom Assembly.

Defining a Custom Assembly


Defining a Custom Assembly implies inheritance from an application provided by the Smart 3D
Custom Assembly base class such as EquipmentAssemblyDefinition,
FootingCustomAssemblyDefinition, or EquipmentFoundationCustomAssemblyDefinition.
These base classes provide a basis for working with the business object and existing Smart 3D
user interface.

Defining Assembly Outputs


Assembly outputs are declared as fields of your Custom Assembly.
' Declare assembly outputs
<AssemblyOutput(1, "Pier")> _
Public m_Pier As AssemblyOutput
<AssemblyOutput(2, "Grout")> _
Public m_Grout As AssemblyOutput

The field variable must be declared Public and have a defining attribute providing it with a unique index
and name. Omitting the defining attribute from the output simply ignores the declared output.

Creating and Evaluating Assembly Outputs


Construction and modification of assembly outputs occurs in the EvaluateAssembly method.
This method is invoked immediately following the symbol’s ConstructOutputs method. All
parameter inputs and symbol outputs are available for you to access when manipulating the
assembly outputs.

Creating Assembly Outputs


Create assembly outputs by setting the declared field assembly output’s field variable Output
property to a persistent business object. EvaluateAssembly is invoked when the outputs are to
be created and anytime the assembly needs to be evaluated. Therefore, it is the responsibility of
the developer to determine whether the output is already generated. A typical pattern for creating
an assembly output might appear as:

If (m_NozzleSuction.Output Is Nothing) Then


m_NozzleSuction.Output = ConstructNozzleSuction(oSP3DConnection)
End If

98 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols

The code always checks whether the output already exists and only constructs the output when it
is Nothing. Failure to make this check results in an exception indicating that the output already
exists.

Modifying Assembly Outputs


As noted earlier, output already exists with subsequent invocations of the EvaluateAssembly
method. To modify the output, cast the output to the constructed business object class and
manipulate the object:

<AssemblyOutput(2, SPSSymbolConstants.Pier)> _
Public m_oPierAssemblyOutput As AssemblyOutput
.
.

Public Overrides Sub EvaluateAssembly()


Dim oPierComponent As FoundationComponent = Nothing

' Construct the pier (if not generated yet).


If m_oPierAssemblyOutput.Output Is Nothing Then
oPierComponent = CreateComponent(SPSSymbolConstants.Pier)
m_oPierAssemblyOutput.Output = oPierComponent
Else
oPierComponent = DirectCast(m_oPierAssemblyOutput.Output,
FoundationComponent)
End If

oPierComponent.Origin = New Position(1, 2, 3)


.
.

Optional Assembly Outputs


Even though an assembly output has been declared, it does not imply that you must create an
output. Not constructing an output indicates the output is not required. Additionally, if an output
already exists, you can remove the output:
If m_oPierAssemblyOutput.Output Is Nothing Then
m_oPierAssemblyOutput.Delete()
End If
Now using this code, the output no longer exists. When the evaluation method is invoked again,
you can decide whether to construct the output again.

Accessing Object Inputs


While constructing and evaluating the assembly outputs, access to the object inputs may be
required; such as the structural member where the footing is to be placed. These inputs must be
retrieved from the business object using the Occurrence property on the Custom Assembly:
'Accessing the footing business object.
Dim oFooting As Footing = DirectCast(Occurrence, Footing)

Intergraph Smart™ 3D .NET Programmer’s Guide 99


Creating .NET Symbols

Direct casting of the occurrence to the specific business object provides access to the object-
specific properties that include the inputs (supported members and supporting members in the
example above).

Allowing End Users to Delete Assembly Outputs


By default an end user cannot remove the assembly outputs of a Custom Assembly without
removing the parent business object. To allow independent removal of an output, you must set
the property CanDeleteIndependently to true. By setting this property to true in your
EvaluateAssembly method, an end user can delete your assembly output independently of the
parent business object. By allowing this behavior, the object construction is slightly complicated
since a check now is necessary to determine whether the user has deleted your output. The object
construction checks would now appear as:
' Construct the pier (if not generated yet).
Dim oPierComponent As FoundationComponent = Nothing
If m_oPierAssemblyOutput.Output Is Nothing Then
If Not m_oPierAssemblyOutput.HasBeenDeletedByUser Then
m_oPierAssemblyOutput.CanDeleteIndependently = True
oPierComponent = CreateComponent("Pier")
m_oPierAssemblyOutput.Output = oPierComponent
End If
Else
oPierComponent = DirectCast(m_oPierAssemblyOutput.Output,
FoundationComponent)
End If
Notice the additional check as to whether the output was deleted by the user with the
HasBeenDeletedByUser property. This property will be true when the output existed at one time
and was explicitly removed by the user. Also, notice the line of code that set the
CanDeleteIndependently property to true, which allowed the user to delete the assembly
output in the first place.

Dynamic Outputs
Similar to a symbol, Custom Assembly provides for dynamic outputs (i.e., outputs with a count
which may vary dynamically at runtime). An example of this might be the structural member
legs of an equipment foundation. Declaring a dynamic output can appear similar to the
following:
' Declaring a dynamic structural member leg output.
<AssemblyOutput(1, "FoundationMemberlegs”)> _
Public m_objFoundationLegs As AssemblyOutputs
The definition of a field variable of type AssemblyOutputs with same AssemblyOutput
defining attribute as present for singularly declared assembly outputs. AssemblyOutputs inherits
from List<BusinessObject>; hence, AssemblyOutputs is a collection (i.e., list) of

100 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating .NET Symbols

BusinessObjects. The code within the EvaluateAssembly method can add and subtract business
objects from this list based on the desired count:
<InputString(2, "FoundationShape", "Foundation Shape", "Rectangle")> _
Public m_sFoundationShape As InputString

<AssemblyOutput(1, "FoundationLegs")> _
Public m_objFoundationLegs As AssemblyOutputs

' Evaluate assembly outputs.


Public Overrides Sub EvaluateAssembly()
Dim iLegCount As Integer
iLegCount = 0

If m_sFoundationShape.Value = "Rectangle" Then


iLegCount = 4
ElseIf m_sFoundationShape.Value = "Hexagon" Then
iLegCount = 6
End If

' Current leg count.


Dim iCurrentLegCount As Integer
iCurrentLegCount = m_objFoundationLegs.Count

Dim iCnt As Integer


If iCurrentLegCount = iLegCount Then ' No change.
ElseIf iCurrentLegCount < iLegCount Then ' Need to add some legs.
For iCnt = iCurrentLegCount + 1 To iLegCount
m_objFoundationLegs.Add(New Member(...
Next
Else ' remove some legs
For iCnt = iCurrentLegCount To iLegCount + 1 Step -1
m_objFoundationLegs.RemoveAt(iCnt)
Next
End If

Bulkloading a Custom Assembly


Bulkloading a Custom Assembly varies slightly from bulkloading a symbol definition.

The Custom Assembly ProgID (in this case, assembly .dll name with custom assembly class
name and its namespace), defined in the Definition field of a bulkloaded spreadsheet, indicates a
Custom Assembly.

Intergraph Smart™ 3D .NET Programmer’s Guide 101


Creating .NET Symbols

When this field exists in the spreadsheet for items such as equipment, footings, equipment
foundations, etc., it is expected that the Definition field should be completed with the name of a
Custom Assembly. The SymbolDefinition is left blank (i.e., this field is ignored).

102 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Batch Commands for Project Management

Creating Batch Commands for Project


Management
Batch commands consist of two main parts – job submission and job execution.

Job Submission
Batch jobs can be scheduled for submission by using the scheduler form or programmatically.

Using the Scheduler Form


1. Reference {Product
Path|\Core\Container\Bin\Assemblies\Release\PrjMgmtClientServices.dll for your new
batch command project.
2. Create an object of the JobScheduler class:
/// <param name="jobName">Name of the job on the Intergraph Batch
Services
/// (IBS).</param>
/// <param name="jobProgID">ProgID of component containing actual
/// implementation.</param>
private JobScheduler jobScheduler;

jobScheduler = new JobScheduler(jobName,jobProgID);

3. Create a button named “SubmitJob” on the batch command form. This name can be
changed at any time by the user.
The Framework provides a method for determining whether or not IBS available. This
button can be enabled or disabled based on the IBS availability.

if (JobScheduler.IsBatchServicesAvailable)
{
// Enable submit button
}

4. Create the object of JobScheduler class to display the scheduler user form, which allows
the user to submit the batch job to the Intergraph Batch Server.
When a user selects required inputs and clicks the Submit Job button, the scheduler form
will be displayed. Call the Show method on JobScheduler to display the scheduler form.
The Show method returns an enumerator value (DialogResult_OK or
DialogResult_CANCEL) based on the user’s selection with the scheduler form. The
batch command should contain the code for whether or not to submit the job.
/// <param name="caption">Caption of the scheduler form.</param>
DialogResult dr = jobScheduler.Show(caption);

Intergraph Smart™ 3D .NET Programmer’s Guide 103


Creating Batch Commands for Project Management

If the user clicks OK, the job should be submitted accordingly.


5. Call SubmitJob to submit the job for batch services (IBS).
/// <param name="CommandArgs">Command line arguments in XML format, required to run
/// the job.</param>
/// <param name="canRusAs64BitJob">True, if the created process is 64-bit.</param>
jobScheduler.SubmitJob(CommandArgs, canRunAs64BitJob);

Submitting a Job Programmatically


1. Reference {Product Path|\Core\Container\Bin\Assemblies\Release\PrjMgmtMiddle.dll
for your new batch command project
2. Create the BatchServices class object, which provides the APIs for scheduling a job.
BatchServices batchServices = new BatchServices();

3. Create the Schedule class object in which to submit the job at any time.
JobInfo class has a Schedule property that gets or sets the timing schedule instance as the
Schedule object. This allows you to specify date, time, and interval details if the enumerated
type is not “RunNow”.
Schedule dailySchedule = new Schedule();
dailySchedule.Type = TaskScheduler.TriggerType.RunDaily;
dailySchedule.Begin = new DateTime(DateTime.Now.Year,
DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour,
DateTime.Now.Minute, DateTime.Now.Second);
dailySchedule.End = new DateTime(DateTime.Now.Year + 1,
DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour,
DateTime.Now.Minute, DateTime.Now.Second);
dailySchedule.Intervals.DaysInterval = 2;

4. Create the JobInfo class object to provide all job-related information as input for
scheduling properties that must be set before submitting the job.
JobInfo jobinfo = new JobInfo();
jobinfo.JobName = JobName;
jobinfo.QueueName = QueueName;
jobinfo.CommandProgId = CmdProgID;
jobinfo.CommandArgsInXMLFormat = cmdArgs;
jobinfo.MailAddressList = "user@intergraph.com";
jobinfo.MailNotificationFlags = JobNotificationFlagsVal;
jobinfo.TriggerType = TaskScheduler.TriggerType.RunNow;
jobinfo.CanRunAs64BitJob = false;

104 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Batch Commands for Project Management

jobinfo.Schedule = dailySchedule;

5. Call the SubmitJob method with jobinfo reference.


Boolean IsJobSubmitted = batchServices.SubmitJob(jobinfo);

Job Execution
Implement the IBatchMiddleCommand with Initialize and Execute methods.
• Initialize method – stores input arguments information to use for the Execute method.
For example:
public override bool Initialize(JobInfo jobInfo)
{
try
{
bool functionReturnValue = false;

//Read XML and store inputs


if
(ParseXMLAndStoreInputs(jobInfo.CommandArgsInXMLFormat)==false)
{
LogBatchMessage("Failed while parsing the XML
and storing the inputs");

}
else
{
functionReturnValue = true;
}
return functionReturnValue;
}
catch (Exception e)
{
LogBatchMessage(e.Message);
return false;
}
}

• Execute method – provides actual implementation, which is executed when the


scheduled job is triggered. For example:
public override bool Execute(ref string strLogFiles, ref string
strErrorLogFiles)

// Real implementation of batch command

Intergraph Smart™ 3D .NET Programmer’s Guide 105


Creating Batch Commands for Project Management

106 Intergraph Smart™ 3D .NET Programmer’s Guide


Creating Batch Commands for Project Management

Configuring Queues for a Custom Batch Job


1. Add the respective job name and job ProgID of your batch command to the
CustomBatchJobDetails.xml file, which is located in the {Product
Path}\SharedContent\Xml folder. If the file does not exist, create a new file using
following format:
<JOB>
<JobType>Check Database Integrity</JobType>
<JobDescription>To check the S3D database integrity and
consistency.</JobDescription>
<JobProgId>BatchSvcCmds,Ingr.SP3D.ProjectMgmt.Client.Commands.BatchR3DMultip
leUpdate </JobProgId>
<IsModelSpecific>True</IsModelSpecific>
</JOB>

JobType Name of the job. Must be unique.

JobDescription Brief description of the job.

JobProgId Custom batch job ProgID.

IsModelSpecific Specifies whether the job is Site-specific or Model-specific; false = Site


and true = Model.

2. Add your new DLL to the {Product Path}\SharedContent\Custom Symbols folder.


3. Run the Update Custom Symbol Configuration executable, which adds the information to
the CustomSymbolConfig.xml file.
Finally in Project Management, Administrators can configure queues for custom batch jobs using
the Configure Queues for Jobs form.

Intergraph Smart™ 3D .NET Programmer’s Guide 107


Reference Data Calculation Rules

Reference Data Calculation Rules

108 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

Custom Wall Thickness and Branch


Reinforcement Calculation
You can now create your own .NET projects with calculation logic for wall thickness and branch
reinforcement by completing the following steps:
• Create a .NET project framework.
• Write calculation logic for the wall thickness calculation.
• Write calculation logic for the branch reinforcement calculation.
• Provide calculation logic ProgIDs for worksheets by adding data to codelist sheets and
piping specification data and then bulkload entries.

Creating a .NET Project for a New Rule


Create a project for the rule.
1. Open Visual Studio and click, File > New > Project. Define as Visual Basic or Visual
C#. Select Windows > Class Library to create a new .NET Class Library project.
2. Change the Project name to RuleCalculation Example for BranchReinforcement and
WallThickness, named as BranchReinforcementAndWallThicknessCalc.
3. Change the name of the class from class1 to MyDesignStandard and append
accordingly, BranchReinforcementRule and WallThicknessRule.
4. Save the Project and the Class.
Add the reference to the following DLLs.
{Product Path}\Core\Container\Bin\Assemblies\Release\RefdataRuleBase.dll
{Product Path}\Core\Container\Bin\Assemblies\Release\ReferenceDataMiddle.dll
{Product Path}\Core\Container\Bin\Assemblies\Release\CommonMiddle.dll
Calculation ProgID Specifications
The calculation ProgID for wall thickness calculation will be
BranchReinforcementAndWallThicknessCalc, Ingr.SP3D.ReferenceData.Middle.
MyDesignStandardWallThicknessRule implements the abstract class
WallThicknessCalculationRuleBase.
public override double GetWallThicknessData(PipeSpec pipeSpec,
PipeInfo pipeInfo, ref double minCalculatedThickness, ref int
schedule)
{
}

Intergraph Smart™ 3D .NET Programmer’s Guide 109


Reference Data Calculation Rules

The calculation ProgID for branch reinforcement will be


BranchReinforcementAndWallThicknessCalc, Ingr.SP3D.ReferenceData.Middle.
MyDesignStandardBranchReinforcementRule implements the abstract class
BranchReinforcementCalculationRuleBase.

110 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

Following overridden methods are provided depending on the type of reinforcement, such as
weld or pad.
public override BranchReinforcementData
GetBranchReinforcementPadData(PipeSpec pipeSpec, PipeComponent
pipePart, PipeStock headerPipeStock, PipeStock branchPipeStock,
HeaderAndBranchInfo headerAndBranchInfo)
{
}

public override BranchReinforcementData


GetBranchReinforcementWeldData(PipeSpec pipeSpec, PipeStock
headerPipeStock, PipeStock branchPipeStock, HeaderAndBranchInfo
headerAndBranchInfo)
{
}

Calculation Logic ProgIDs for Worksheets


1. Add an entry to the DesignStandard codelist sheet and bulkload into the database.

2. Add an entry to the ScheduleThickness codelist sheet and bulkload into the database.

3. Using the ProgID of the calculation program,


BranchReinforcementAndWallThicknessCalc, Ingr.SP3D.ReferenceData.Middle
and MyDesignStd’RuleType’, add an entry to the CalculationProgIDs sheet and
bulkload into the database.

Intergraph Smart™ 3D .NET Programmer’s Guide 111


Reference Data Calculation Rules

4. Add data to the MaterialsData sheet and bulkload into the database.

5. Set the DesignStandard on the PipingMaterialsClassData sheet.

112 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

Calculation Logic for the Wall Thickness


Calculation
Add code to the following GetWallThicknessData function for wall thickness calculation. It is
called by the software that invokes calculation logic and its specified argument values.
/// <summary>
/// Returns the wall thickness calculation value.
/// </summary>
/// <param name="pipeSpec">Pipe specification class as
PipeSpec.</param>
/// <param name="pipeInfo">PipeInfo class, which contains all the pipe
/// information.</param>
/// <param name="minCalculatedThickness">Minimum calculated
/// thickness.</param>
/// <param name="schedule">The pipe schedule.</param>
public override double GetWallThicknessData(PipeSpec pipeSpec,
PipeInfo pipeInfo, out double minCalculatedThickness, out int
schedule)
{

double calculatedWallThickness = 0;
CatalogOutfittingHelper pipingServices = new
CatalogOutfittingHelper();

//internal design gauge pressure


double gagePressure = 0;
//pipe outside diameter
double outsideDiameter = 0;
//allowable stress in tension
double allowableStress = 0;
//joint quality factor
double jointQualityFactor = 0;
//coefficient for material
double materialCoefficient = 0;
//calculated thickness
double CalculatedThickness = 0;
//mill tolerance
double millTolerence = 0.0;
//is mill tolerance percentage
bool isMillTolerancePercent = false;
//low end of the wall thickness range
double wallThicknessRangeLowEnd = 0;
//high end of the wall thickness range
double wallThicknessRangeHighEnd = 0;
//thread thickness for threaded pipe, if applicable, from the
thickness data rule
double threadThickness = 0;
//minimum thickness from thickness data rule

Intergraph Smart™ 3D .NET Programmer’s Guide 113


Reference Data Calculation Rules

double minimumThickness = 0;
//retirement thickness from the thickness data rule
double retirementThickness = 0;
//uncorroded thickness
double uncorrodedThickness = 0;
//minimum calculated thickness
double minimumCalculatedThickness = 0;
//required thickness
double requiredThickness = 0;
//corrosion allowance from the Corrosion Allowance rule
double corrosionAllowence = 0;
//nominal pipe thickness
double nominalPipeThickness = 0;
//minimum wall thickness permissible under purchase specification
double minimumWallThickness = 0;
//required minimum wall thickness
double requiredMinimumWallThickness = 0;
//mill tolerance
double millToleranceVal = 0;
//pressure design thickness
double pressureDesignThickness = 0;

minCalculatedThickness = 0.0;
schedule = 0;
long ii = 0;

if (pipeSpec == null)
{
throw new CmnArgumentNullException("pipeSpec");
}
if (pipeInfo == null)
{
throw new CmnArgumentNullException("pipeInfo");
}

try
{

DataSet dataSet = null;

outsideDiameter = pipeInfo.PipeOutsideDiameter;
try
{
jointQualityFactor = pipeSpec.GetJointQualityFactor(pipeInfo.NPD,
pipeInfo.PipeStockCommodityOption);
}
catch (Exception )
{
this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.E_FAIL , "Error while
calculating joint quality factor");
}

114 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

try
{
dataSet = pipingServices.GetMaterialsData(pipeSpec,
pipeInfo.MaterialCategory, pipeInfo.Temperature);
}
catch (Exception )
{
this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.E_FAIL, "Error while
getting Materials data");
}

if (Utilities.GetInterpolatedSYFromMaterialsDataRule(dataSet,
pipeInfo.Temperature, ref allowableStress, ref materialCoefficient))
{
this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.REFDATAMATERIALNOTFOUNDEXC
EPTION , "RefData material not found ");
}

Utilities.ConvertPressureOrStressToGageUnits(pipeInfo.Pressure, ref
gagePressure);

CalculatedThickness = (gagePressure * outsideDiameter) / (2.0 *


(allowableStress * (jointQualityFactor / 100) + gagePressure *
materialCoefficient));

int count;

do
{
count = 0;
wallThicknessRangeLowEnd = Utilities.GetRecordsFromDataset(dataSet,
"WallThicknessFrom");
wallThicknessRangeHighEnd = Utilities.GetRecordsFromDataset(dataSet,
"WallThicknessTo");

if ((CalculatedThickness < (outsideDiameter / 6.0)) &&


((Math.Abs(wallThicknessRangeLowEnd - Utilities.DOUBLEZERO) ==
Math3d.DistanceTolerance) || (CalculatedThickness >=
wallThicknessRangeLowEnd)) && ((Math.Abs(wallThicknessRangeHighEnd -
Utilities.DOUBLEZERO) == Math3d.DistanceTolerance) ||
(CalculatedThickness <= wallThicknessRangeHighEnd)))
{
millTolerence = Utilities.GetRecordsFromDataset(dataSet,
"MillTolerance");
}

if (Math.Abs(millTolerence - Utilities.DOUBLEZERO) ==
Math3d.DistanceTolerance)
{

Intergraph Smart™ 3D .NET Programmer’s Guide 115


Reference Data Calculation Rules

millTolerence = Utilities.GetRecordsFromDataset(dataSet,
"MillTolerancePercentage");
millTolerence = millTolerence / 100;
if (Math.Abs(millTolerence - Utilities.DOUBLEZERO) ==
Math3d.DistanceTolerance)
{
this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.E_FAIL, "Error while
calculating mill tolerance");
}
isMillTolerancePercent = true;
}
else
{
isMillTolerancePercent = false;
}

} while (count <= dataSet.Tables[0].Rows.Count);

PreferredSchedule prefferedSchedule = new PreferredSchedule();


try
{
pipeSpec.GetThicknessData(pipeInfo.NPD, out minimumThickness, out
retirementThickness, out threadThickness, ref prefferedSchedule);
}
catch (Exception )
{
this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.E_FAIL, "Error while
calculating thickness data");
}

if ((CalculatedThickness > retirementThickness))


{
uncorrodedThickness = CalculatedThickness;
}
else
{
uncorrodedThickness = retirementThickness;
}

try
{
corrosionAllowence =
pipeSpec.CorrosionAllowance(pipeInfo.MaterialCategory,
pipeInfo.FluidCode);
}
catch (Exception )
{
this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.E_FAIL, "Error while
calculating corrosion allowance");

116 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

if (isMillTolerancePercent)
{
minimumCalculatedThickness = (uncorrodedThickness + corrosionAllowence
+ threadThickness) / (1 - millTolerence);
}
else
{
minimumCalculatedThickness = uncorrodedThickness + corrosionAllowence
+ threadThickness + millTolerence;
}

if ((minimumCalculatedThickness > minimumThickness))


{
requiredThickness = minimumCalculatedThickness;
}
else
{
requiredThickness = minimumThickness;
}

minCalculatedThickness = minimumCalculatedThickness;

PipePortProperties pipeportProperties = new PipePortProperties();

int[] lPreferredSchedule = new int[6];

for (ii = 1; ii <= Utilities.TOTALPREFERREDSCHEDULES; ii++)


{
if (lPreferredSchedule[ii] == Utilities.CODELISTVALUE_UNDEFINED ||
lPreferredSchedule[ii] == Utilities.CODELISTVALUE_DEFAULT)
{
ii = Utilities.TOTALPREFERREDSCHEDULES + 1;
break;
}

pipeportProperties.EndPreparation = pipeInfo.EndPreparation;
pipeportProperties.EndStandard = pipeInfo.EndStandard;
pipeportProperties.Npd = pipeInfo.NPD.Size;
pipeportProperties.NpdUnitType = pipeInfo.NPD.Units;
pipeportProperties.PressureRating = pipeInfo.PressureRating;
pipeportProperties.Schedule = Convert.ToInt32(schedule);
pipeportProperties.PipingPointBasis = pipeInfo.PipingPointBasis;
pipeportProperties.GeometricIndustryStd =
pipeInfo.GeometricIndustryStandard;
pipeportProperties.LiningMaterial = pipeInfo.LiningMaterial;
schedule = lPreferredSchedule[ii];

try
{

Intergraph Smart™ 3D .NET Programmer’s Guide 117


Reference Data Calculation Rules

nominalPipeThickness =
pipeSpec.GetNominalPipeThickness(pipeportProperties);
}
catch (Exception )
{
this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.E_FAIL, "Error while
calculating Nominal Pipe Thickness ");
}

if (requiredThickness < nominalPipeThickness)


{
//required thickness is sufficient for wall thickness calc
break; // TODO: might not be correct. Was : Exit For
}
}

if (ii > Utilities.TOTALPREFERREDSCHEDULES)


{
this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.REFDATANOPARTSEXCEPTION ,
"RefData no part found ");
}

if (isMillTolerancePercent)
{
millToleranceVal = nominalPipeThickness * millTolerence;
}
else
{
millToleranceVal = millTolerence;
}

if ((minimumCalculatedThickness >= minimumThickness &&


retirementThickness >= CalculatedThickness))
{
requiredMinimumWallThickness = requiredThickness;
minimumWallThickness = nominalPipeThickness - millToleranceVal;
pressureDesignThickness = requiredThickness - millToleranceVal -
corrosionAllowence;
}
else
{
requiredMinimumWallThickness = uncorrodedThickness + millToleranceVal
+ corrosionAllowence;
minimumWallThickness = nominalPipeThickness - millToleranceVal;
pressureDesignThickness = uncorrodedThickness;
}

}
catch (Exception)

118 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

{
this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.E_FAIL, "Error while
calculating wall thickness");

}
finally
{

calculatedWallThickness = minimumCalculatedThickness;
return calculatedWallThickness;

}
}

Intergraph Smart™ 3D .NET Programmer’s Guide 119


Reference Data Calculation Rules

Calculation Logic for the Branch Reinforcement


Calculation
To write calculation logic for the Branch Reinforcement calculation for weld or padded types,
use the following two functions, provided as example code in this section. These methods are
called by the software that invokes calculation logic and each of their specified argument values.

GetBranchReinforcementPadData Method
/// <summary>
/// Returns the BranchReinforcementData object, which contains values
for
/// ReinforcingPadThickness and ReinforcingPadWidth.</summary>
/// <param name="pipeSpec">Pipe specification class as
PipeSpec.</param>
/// <param name="pipePart">Pipe part as PipeComponent class.</param>
/// <param name="headerPipeStock">Header pipe stock as
PipeStock.</param>
/// <param name="branchPipeStock">Branch pipe stock as PipeStock
</param>
/// <param name="headerAndBranchInfo">Contains all the properties on
header
/// and branch pipe stock.</param>
public override BranchReinforcementData
GetBranchReinforcementPadData(PipeSpec pipeSpec, PipeComponent
pipePart, PipeStock headerPipeStock, PipeStock branchPipeStock,
HeaderAndBranchInfo headerAndBranchInfo)
{

if (pipeSpec == null)
{
throw new CmnArgumentNullException("pipeSpec");
}

if (pipePart == null)
{
throw new CmnArgumentNullException("pipePart");
}

if (headerPipeStock == null)
{
throw new CmnArgumentNullException("headerPipeStock");
}

if (branchPipeStock == null)
{
throw new CmnArgumentNullException("branchPipeStock");

120 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

if (headerAndBranchInfo == null)
{
throw new CmnArgumentNullException("headerAndBranchInfo");
}

//Default message for the error if anything else happened apart from
all the mentioned error codes
string message = "Error while calculating branch reinforcement";
CatalogOutfittingHelper pipingServices = new
CatalogOutfittingHelper();

BusinessObject BO;
BO = pipeSpec;
PreferredSchedule perferredSchedule = new PreferredSchedule();
BranchReinforcementData branchreinforcementData = new
BranchReinforcementData();

#region header and Branch properties variables


NominalDiameter headerNPD = new NominalDiameter(), branchNPD = new
NominalDiameter();
double headerOutsideDiameter = 0;
int headerMaterialsGrade = 0;
int headerMaterialsCategory = 0;
int headerSchedule = 0;
int headerSchedulePractice = 0;
int headerEndPrep = 0;
int headerEndStd = 0;
int headerPressureRating = 0;
int headerTerminationClass = 0;
int headerTerminationSubClass = 0;
int headerPipingPointBasis = 0;
int headerGeoIndStd = 0;

double branchOutsideDiameter = 0;
int branchMaterialsGrade = 0;
int branchMaterialsCategory = 0;
int branchSchedule = 0;
int branchSchedulePractice = 0;
int branchEndPrep = 0;
int branchEndStd = 0;
int branchPressureRating = 0;
int branchTerminationClass = 0;
int branchTerminationSubClass = 0;
int branchPipingPointBasis = 0;
int branchGeoIndStd = 0;
#endregion

#region Header PipeStock Variables

Intergraph Smart™ 3D .NET Programmer’s Guide 121


Reference Data Calculation Rules

//internal design gauge pressure for header


double headerPressureGauge = 0;
//header outside diameter
double headerOutDiameter = 0;
//allowable stress in tension for the header
double headerallowableStress = 0;
//joint quality factor for the header
double headerJointQualityFactor = 0;
//coefficient for header material
double headerMaterialCoefficient = 0;
//calculated header thickness
double headerCalcThickness = 0;
//mill tolerance
double headerMillTolerance = 0.0;
//is mill tolerance percentage
bool headerMillTolerancePercent = false;
//low end of the wall thickness range
double headerlowThicknessRange = 0.0;
//high end of the wall thickness range
double headerHighThicknessRange = 0.0;
//thread thickness for threaded pipe, if applicable, from the
Thickness Data rule
double headerThreadThickness = 0;
//minimum header thickness from thickness data rule
double headerMinThickness = 0;
//retirement thickness from the thickness data rule
double headerRetirementThickness = 0;
//uncorroded header thickness
double headerUncorrodedThickness = 0;
//minimum calculated header thickness
double headerMinCalThickness = 0;
//required header thickness
double headerRequiredThickness = 0;
//header corrosion allowance from the Corrosion Allowance rule
double headerCorrosionAllownace = 0;
//nominal header pipe thickness
double headernominalPipeThickness = 0;
//minimum header wall thickness permissible under purchase
specification
double headerMinWallThickness = 0;
//header mill tolerance
double headerMillToleranceVal = 0;
//required minimum wall thickness for header
double headerRequiredMinWallThickness = 0;
//additional thickness
double headerAdditionalThickness = 0;
//excess header thickness
double headerExcessThickness = 0;
//header pressure design thickness
double headerPressureDesignThickness = 0;
#endregion

122 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

#region Branch PipeStock Variables

//internal design gauge pressure for branch


double branchPressureGauge = 0;
//branch outside diameter
double branchOutDiameter = 0;
//allowable stress in tension for the branch
double branchAllowableStress = 0;
//joint quality factor for the branch
double branchJointQualityFactor = 0;
//coefficient for branch material
double branchMaterialCoefficient = 0;
//calculated branch thickness
double branchCalcThickness = 0;
//mill tolerance
double branchMillTolerance = 0;
//is mill tolerance percentage
bool branchMilltolerancePercentage = false;
//low end of the wall thickness range
double branchLowThicknessRange = 0;
//high end of the wall thickness range
double branchHighThicknessRange = 0;
//thread thickness for threaded pipe, if applicable, from the
Thickness Data rule
double branchThreadThickness = 0;
//minimum branch thickness from thickness data rule
double branchMinThickness = 0;
//retirement thickness from the thickness data rule
double branchRetirementThickness = 0;
//uncorroded branch thickness
double branchUncorrodedThickness = 0;
//minimum calculated branch thickness
double branchMinCalThickness = 0;
//required branch thickness
double branchRequiredThickness = 0;
//branch corrosion allowance from the Corrosion Allowance rule
double branchCorrosionAllowance = 0;
//nominal branch pipe thickness
double branchNominalPipeThickness = 0;
//minimum branch wall thickness permissible under purchase
specification
double branchMinWallThickness = 0;
//branch mill tolerance
double branchMillToleranceVal = 0;
//required minimum wall thickness for branch
double branchRequiredWallThickness = 0;
//additional thickness
double branchAdditionalThickness = 0;
//excess branch thickness
double branchExcessThickness = 0;

double t_b = 0;

Intergraph Smart™ 3D .NET Programmer’s Guide 123


Reference Data Calculation Rules

#endregion

#region Reinforcement variables

//minimum reinforcement thickness


double minimumReinforcementThickness = 0;
//height of reinforcement zone outside of pipe run
double reinforcementHeightOutsidePipeRun = 0;
//effective length removed from pipe at branch
double lengthRemovedFromPipe = 0;
//half width of reinforcement zone
double retirementZoneHalfWidth = 0;
//required reinforcement area
double requiredReinforcementArea = 0;
//reinforcement area resulting from the excess thickness in the header
pipe wall
double reinforcmentAreaExcessHeader = 0;
//reinforcement area resulting from the excess thickness in the branch
pipe wall
double reinforcmentAreaExcessBranch = 0;
//reinforcement area resulting from the branch welds
double reinforcingAreaBranchWeld = 0;
//total available reinforcement area
double totalReinforcementArea = 0;
//minimum leg dimension of branch fillet weld
double branchFilletWeldDimension = 0;
//throat thickness of cover fillet weld
double coverFillerWeldThroatThickness = 0;

//reinforcement area resulting from the branch welds


double branchWeldReinforcementArea = 0;
//calculated half thickness of reinforcing pad
double halfThicknessReinforcementPad = 0;
// available branch pad weld size
double branchPadSizeAvaialble = 0;
//size of reinforcing pad fillet weld on header
double headerReinforcementPadFillet = 0;
//minimum head dimension of header pad fillet weld
double headerPadMinDimension = 0;
//reinforcement area resulting from the header welds
double headerWeldReinforcmentArea = 0;
//reinforcement height
double reinforcmentHeight = 0;
//header allowable stress
double headerAllowableStress = 0;
//branch allowable stress
double branchAllowbleStress = 0;
//reinforcing pad allowable stress
double reinforcingPadAllowableStress = 0;
//allowable stress ratio to account for any differences in material

124 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

double allowableStressRatio = 0;
//pad reinforcement area
double reinfocementPadArea = 0;
//calculated reinforcing pad width
double reinforcingPadCalculatedWidth = 0;
//minimum reinforcing pad width from reinforcing pad data rule
double reinforcingPadMinimumWidth = 0;
//calculated half width of reinforcing pad
double reinforcingPadhalfWidth = 0;
//reinforcing pad thickness
double reinforcingPadThickness = 0;
//reinforcing pad width
double reinforcingPadWidth = 0;
//allowable stress in tension for the reinforcing pad
double reinforcingPadAllowableStressinTension = 0;

double Y_pad = 0;
#endregion

try
{
IPipeComponent pipeComponent;
pipeComponent = headerPipeStock;
Part part = (Part)pipeComponent;

ReadOnlyCollection<BusinessObject> ports = part.PortDefinitions;

//for the header pipe stock


headerNPD = pipeComponent.PrimaryNPD;
headerMaterialsGrade = pipeComponent.MaterialGrade;
headerMaterialsCategory = pipeComponent.MaterialCategory;
headerGeoIndStd = pipeComponent.GeometricIndustryStandard;

PipePortDef headerPipePortDef = (PipePortDef)ports.ElementAt(1);

headerOutsideDiameter = headerPipePortDef.PipingOutsideDiameter;
headerEndPrep = headerPipePortDef.EndPreparation;
headerEndStd = headerPipePortDef.EndStandard;
headerPressureRating = headerPipePortDef.PressureRating;
headerSchedule = headerPipePortDef.ScheduleThickness;
headerSchedulePractice = headerPipePortDef.SchedulePractice;
headerTerminationClass = headerPipePortDef.TerminationClass;
headerTerminationSubClass = headerPipePortDef.TerminationSubClass; ;
headerPipingPointBasis = headerPipePortDef.PipingPointBasis;

pipeComponent = branchPipeStock;
Part branchpart = (Part)pipeComponent;

ReadOnlyCollection<BusinessObject> branchports =
branchpart.PortDefinitions;

Intergraph Smart™ 3D .NET Programmer’s Guide 125


Reference Data Calculation Rules

//for the branch pipe stock

branchNPD = pipeComponent.PrimaryNPD;
branchMaterialsGrade = pipeComponent.MaterialGrade;
branchMaterialsCategory = pipeComponent.MaterialCategory;
branchGeoIndStd = pipeComponent.GeometricIndustryStandard;

PipePortDef branchPipePortDef = (PipePortDef)branchports.ElementAt(1);

branchOutsideDiameter = branchPipePortDef.PipingOutsideDiameter;
branchEndPrep = branchPipePortDef.EndPreparation;
branchEndStd = branchPipePortDef.EndStandard;
branchPressureRating = branchPipePortDef.PressureRating;
branchSchedule = branchPipePortDef.ScheduleThickness;
branchSchedulePractice = branchPipePortDef.SchedulePractice;
branchTerminationClass = branchPipePortDef.TerminationClass;
branchTerminationSubClass = branchPipePortDef.TerminationSubClass; ;
branchPipingPointBasis = branchPipePortDef.PipingPointBasis;

headerOutDiameter = headerOutsideDiameter;
//Get the header Joint Quality factor

try
{
headerJointQualityFactor = pipeSpec.GetJointQualityFactor(headerNPD,
headerAndBranchInfo.HeaderCommodityOption);
}
catch (Exception Ce)
{
throw Ce;
}

//get the data set of materials data rule


DataSet dataset = null;

try
{
dataset = pipingServices.GetMaterialsData(pipeSpec,
headerMaterialsGrade, headerAndBranchInfo.HeaderTemperature);
}
catch (Exception)
{
throw new Utilities.RefDataInsufficientDataException(message);
}

bool isInterpolatedSY = false;

if(dataset != null)
isInterpolatedSY =
Utilities.GetInterpolatedSYFromMaterialsDataRule(dataset,

126 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

headerAndBranchInfo.HeaderTemperature, ref headerallowableStress, ref


headerMaterialCoefficient);

if (isInterpolatedSY == false)
{
message = "MaterialsDataRule does NOT address the calculated header
thickness.";
throw new Utilities.RefDataInsufficientDataException(message);
}

Utilities.ConvertPressureOrStressToGageUnits(headerAndBranchInfo.Heade
rPressure, ref headerPressureGauge);

headerCalcThickness = (headerPressureGauge * headerOutDiameter) / (2.0


* (headerallowableStress * (headerJointQualityFactor / 100) +
headerPressureGauge * headerMaterialCoefficient));

int count = 1;
do
{
headerlowThicknessRange = Utilities.GetRecordsFromDataset(dataset,
"WallThicknessFrom");
headerHighThicknessRange = Utilities.GetRecordsFromDataset(dataset,
"WallThicknessTo");

if ((headerCalcThickness < (headerOutDiameter / 6.0)) &&


((Math.Abs(headerlowThicknessRange - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance || (headerCalcThickness >=
headerlowThicknessRange)) && (Math.Abs(headerHighThicknessRange -
Utilities.DOUBLEZERO) <= Math3d.DistanceTolerance ||
(headerCalcThickness <= headerHighThicknessRange))))
{
headerMillTolerance = Utilities.GetRecordsFromDataset(dataset,
"MillTolerance");

if (Math.Abs(headerMillTolerance - Utilities.DOUBLEZERO) <=


Math3d.DistanceTolerance)
{
headerMillTolerance = Utilities.GetRecordsFromDataset(dataset,
"MillTolerancePercentage");
headerMillTolerance = headerMillTolerance / 100;
if (Math.Abs(headerMillTolerance - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance)
{
throw new CmnException("Error while calculating mill tolerance",
(int)RefDataRuleErrorType.E_FAIL);
}
headerMillTolerancePercent = true;
}
else
{
headerMillTolerancePercent = false;

Intergraph Smart™ 3D .NET Programmer’s Guide 127


Reference Data Calculation Rules

break;
}
count++;
} while (count <= dataset.Tables[0].Rows.Count);

if (Math.Abs(headerMillTolerance - Utilities.DOUBLEZERO) <=


Math3d.DistanceTolerance)
{
//insufficient
message = "MaterialsDataRule does NOT address the calculated header
thickness.";
throw new Utilities.RefDataInsufficientDataException(message);
}

try
{
pipeSpec.GetThicknessData(headerNPD, out headerMinThickness, out
headerRetirementThickness, out headerThreadThickness, ref
perferredSchedule);
}
catch (Exception Ce)
{
throw Ce;
}

if (headerCalcThickness > headerRetirementThickness)


{
headerUncorrodedThickness = headerCalcThickness;
}
else
{
headerUncorrodedThickness = headerRetirementThickness;
}

try
{
headerCorrosionAllownace =
pipeSpec.CorrosionAllowance(headerMaterialsCategory,
headerAndBranchInfo.HeaderFluidCode);
}
catch (Exception Ce)
{
throw Ce;
}

if (headerMillTolerancePercent)
{

128 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

headerMinCalThickness = (headerUncorrodedThickness +
headerCorrosionAllownace + headerThreadThickness) / (1 -
headerMillTolerance);
}
else
{
headerMinCalThickness = headerUncorrodedThickness +
headerCorrosionAllownace + headerThreadThickness +
headerMillTolerance;
}

if ((headerMinCalThickness > headerMinThickness))


{
headerRequiredThickness = headerMinCalThickness;
}
else
{
headerRequiredThickness = headerMinThickness;
}

PipePortProperties pipePortProperties = new PipePortProperties();

pipePortProperties.Schedule = headerSchedule;
pipePortProperties.EndPreparation = headerEndPrep;
pipePortProperties.EndStandard = headerEndStd;
pipePortProperties.Npd = headerNPD.Size;
pipePortProperties.NpdUnitType = headerNPD.Units;
pipePortProperties.PressureRating = headerPressureRating;
pipePortProperties.PipingPointBasis = headerPipingPointBasis;
pipePortProperties.GeometricIndustryStd = headerGeoIndStd;
pipePortProperties.LiningMaterial = 1;

try
{
headernominalPipeThickness =
pipeSpec.GetNominalPipeThickness(pipePortProperties);
}
catch (Exception Ce)
{
throw Ce;
}

if (headerRequiredThickness < headernominalPipeThickness)


{
//required header thickness is sufficient for branch reinforcement
calc
}
else
{
//insufficient
message = "(headerRequiredThickness < headernominalPipeThickness) is
FALSE.";

Intergraph Smart™ 3D .NET Programmer’s Guide 129


Reference Data Calculation Rules

throw new Utilities.RefDataInsufficientDataException(message);


}

if (headerMillTolerancePercent)
{
headerMillToleranceVal = headernominalPipeThickness *
headerMillTolerance;
}
else
{
headerMillToleranceVal = headerMillTolerance;
}

headerAdditionalThickness = headerMillToleranceVal +
headerCorrosionAllownace;

if ((headerMinCalThickness >= headerMinThickness) &&


(headerRetirementThickness >= headerCalcThickness))
{
headerMinWallThickness = headernominalPipeThickness -
headerMillToleranceVal;
headerRequiredMinWallThickness = headerRequiredThickness;
headerExcessThickness = headernominalPipeThickness -
headerRequiredThickness;
headerPressureDesignThickness = headerRequiredThickness -
headerMillToleranceVal - headerCorrosionAllownace;
}
else
{
headerMinWallThickness = headernominalPipeThickness -
headerMillToleranceVal;
headerRequiredMinWallThickness = headerUncorrodedThickness +
headerMillToleranceVal + headerCorrosionAllownace;
headerExcessThickness = headernominalPipeThickness -
headerMillToleranceVal - headerCorrosionAllownace -
headerUncorrodedThickness;
headerPressureDesignThickness = headerUncorrodedThickness;
}

//Definitions of thickness of the branch

//branch pressure design thickness

branchOutDiameter = branchOutsideDiameter;

try
{
branchJointQualityFactor = pipeSpec.GetJointQualityFactor(branchNPD,
headerAndBranchInfo.BranchCommodityOption);

130 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

catch (Exception Ce)


{
throw Ce;
}

try
{
dataset = pipingServices.GetMaterialsData(pipeSpec,
branchMaterialsGrade, headerAndBranchInfo.BranchTemperature);
}
catch (Exception)
{
throw new Utilities.RefDataInsufficientDataException(message);
}

isInterpolatedSY = false;

if (dataset != null)
isInterpolatedSY =
Utilities.GetInterpolatedSYFromMaterialsDataRule(dataset,
headerAndBranchInfo.BranchTemperature, ref branchAllowableStress, ref
branchMaterialCoefficient);

if (isInterpolatedSY == false)
{
//insufficient
message = "MaterialsDataRule does NOT address the calculated branch
thickness.";
throw new Utilities.RefDataInsufficientDataException(message);
}

Utilities.ConvertPressureOrStressToGageUnits(headerAndBranchInfo.Branc
hPressure, ref branchPressureGauge);

branchCalcThickness = (branchPressureGauge * branchOutDiameter) / (2.0


* (branchAllowableStress * (branchJointQualityFactor / 100) +
branchPressureGauge * branchMaterialCoefficient));

//////////////////////////////////////////////////////////////////////
//

int counter = 1;

do
{

branchLowThicknessRange = Utilities.GetRecordsFromDataset(dataset,
"WallThicknessFrom");
branchHighThicknessRange = Utilities.GetRecordsFromDataset(dataset,
"WallThicknessTo");

Intergraph Smart™ 3D .NET Programmer’s Guide 131


Reference Data Calculation Rules

if ((headerCalcThickness < (headerOutDiameter / 6.0)) &&


((Math.Abs(branchLowThicknessRange - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance || (headerCalcThickness >=
branchLowThicknessRange)) && (Math.Abs(branchHighThicknessRange -
Utilities.DOUBLEZERO) <= Math3d.DistanceTolerance ||
(branchCalcThickness <= branchHighThicknessRange))))
{
branchMillTolerance = Utilities.GetRecordsFromDataset(dataset,
"MillTolerance");

if (Math.Abs(branchMillTolerance - Utilities.DOUBLEZERO) <=


Math3d.DistanceTolerance)
{
branchMillTolerance = Utilities.GetRecordsFromDataset(dataset,
"MillTolerancePercentage");
branchMillTolerance = branchMillTolerance / 100;
if (Math.Abs(branchMillTolerance - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance)
{
throw new CmnException("Error while calculating mill tolerance",
(int)RefDataRuleErrorType.E_FAIL);
}
branchMilltolerancePercentage = true;
}
else
{
branchMilltolerancePercentage = false;
}
break;
}

counter++;
} while (counter <= dataset.Tables[0].Rows.Count);

if (Math.Abs(branchMillTolerance - Utilities.DOUBLEZERO) <=


Math3d.DistanceTolerance)
{
//insufficient
message = "MaterialsDataRule does NOT address the calculated branch
thickness.";
throw new Utilities.RefDataInsufficientDataException(message);
}

try
{
pipeSpec.GetThicknessData(branchNPD, out branchMinThickness, out
branchRetirementThickness, out branchThreadThickness, ref
perferredSchedule);

}
catch (Exception Ce)
{

132 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

throw Ce;
}

if ((branchCalcThickness > branchRetirementThickness))


{
branchUncorrodedThickness = branchCalcThickness;
}
else
{
branchUncorrodedThickness = branchRetirementThickness;
}

pipePortProperties = new PipePortProperties();

pipePortProperties.EndPreparation = branchEndPrep;
pipePortProperties.EndStandard = branchEndStd;
pipePortProperties.Npd = branchNPD.Size;
pipePortProperties.NpdUnitType = branchNPD.Units;
pipePortProperties.PressureRating = branchPressureRating;
pipePortProperties.Schedule = branchSchedule;
pipePortProperties.PipingPointBasis = branchPipingPointBasis;
pipePortProperties.GeometricIndustryStd = branchGeoIndStd;
pipePortProperties.LiningMaterial = 1;

try
{
branchNominalPipeThickness =
pipeSpec.GetNominalPipeThickness(pipePortProperties);

}
catch (Exception Ce)
{
throw Ce;
}

if (branchMilltolerancePercentage)
{
branchMillToleranceVal = branchNominalPipeThickness *
branchMillTolerance;
}
else
{
branchMillToleranceVal = branchMillTolerance;
}

try
{
branchCorrosionAllowance =
pipeSpec.CorrosionAllowance(branchMaterialsCategory,
headerAndBranchInfo.BranchFluidCode);

Intergraph Smart™ 3D .NET Programmer’s Guide 133


Reference Data Calculation Rules

catch (Exception Ce)


{
throw Ce;
}

if (branchMilltolerancePercentage)
{
branchMinCalThickness = (branchUncorrodedThickness +
branchCorrosionAllowance + branchThreadThickness) / (1 -
branchMillTolerance);
}
else
{
branchMinCalThickness = branchUncorrodedThickness +
branchCorrosionAllowance + branchThreadThickness +
branchMillTolerance;
}

if ((branchMinCalThickness > branchMinThickness))


{
branchRequiredThickness = branchMinCalThickness;
}
else
{
branchRequiredThickness = branchMinThickness;
}

if (branchRequiredThickness < branchNominalPipeThickness)


{
//required branch thickness is sufficient for branch reinforcement
calc
}
else
{
//insufficient
message = "(branchRequiredThickness < branchNominalPipeThickness) is
FALSE.";
throw new Utilities.RefDataInsufficientDataException(message);
}

branchAdditionalThickness = branchMillToleranceVal +
branchCorrosionAllowance;

if ((branchMinCalThickness >= branchMinThickness &


branchRetirementThickness >= branchCalcThickness))
{
branchMinWallThickness = branchNominalPipeThickness -
branchMillToleranceVal;
branchRequiredWallThickness = branchRequiredThickness;
branchExcessThickness = branchNominalPipeThickness -
branchRequiredThickness;

134 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

t_b = branchRequiredThickness - branchMillToleranceVal -


branchCorrosionAllowance;
}
else
{
branchMinWallThickness = branchNominalPipeThickness -
branchMillToleranceVal;
branchRequiredWallThickness = branchUncorrodedThickness +
branchMillToleranceVal + branchCorrosionAllowance;
branchExcessThickness = branchNominalPipeThickness -
branchMillToleranceVal - branchCorrosionAllowance -
branchUncorrodedThickness;
t_b = branchUncorrodedThickness;
}

if (branchPressureGauge < headerPressureGauge)


{
branchExcessThickness = 0.0;
}

int reinforcingPadMaterialsGrade = 0;
int reinforcingPadMaterialsCategory = 0;
reinforcingPadMaterialsGrade = pipeComponent.MaterialGrade;
reinforcingPadMaterialsCategory = pipeComponent.MaterialCategory;

try
{
dataset = pipingServices.GetMaterialsData(pipeSpec,
reinforcingPadMaterialsGrade, headerAndBranchInfo.HeaderTemperature);

}
catch (Exception Ce)
{
throw Ce;
}

isInterpolatedSY = false;

if (dataset != null)
isInterpolatedSY =
Utilities.GetInterpolatedSYFromMaterialsDataRule(dataset,
headerAndBranchInfo.HeaderTemperature, ref
reinforcingPadAllowableStressinTension, ref Y_pad);

if (isInterpolatedSY == false)
{
//insufficient
message = "MaterialsDataRule does NOT address the reinforcing Pad";
throw new Utilities.RefDataInsufficientDataException(message);
}

if (headerAndBranchInfo.IsBranchReinforcementByUser)

Intergraph Smart™ 3D .NET Programmer’s Guide 135


Reference Data Calculation Rules

{
reinforcingPadThickness =
branchreinforcementData.ReinforcingPadThickness;
}
else
{
reinforcingPadThickness = headernominalPipeThickness;
}

if (headerMillTolerancePercent)
{
minimumReinforcementThickness = reinforcingPadThickness * (1.0 -
headerMillTolerance);
}
else
{
minimumReinforcementThickness = reinforcingPadThickness -
headerMillTolerance;
}

reinforcementHeightOutsidePipeRun = 2.5 * (t_b -


branchAdditionalThickness) + minimumReinforcementThickness;

lengthRemovedFromPipe = (branchOutDiameter - 2.0 *


branchNominalPipeThickness) /
Math.Sin(headerAndBranchInfo.BranchAngle);

retirementZoneHalfWidth = t_b - branchAdditionalThickness +


headerMinWallThickness + lengthRemovedFromPipe / 2.0;

if (retirementZoneHalfWidth < lengthRemovedFromPipe)


{
retirementZoneHalfWidth = lengthRemovedFromPipe;
}

if (retirementZoneHalfWidth > headerOutDiameter)


{
retirementZoneHalfWidth = headerOutDiameter;
}

requiredReinforcementArea = 1.07 * headerRequiredMinWallThickness *


lengthRemovedFromPipe * (2.0 -
Math.Sin(headerAndBranchInfo.BranchAngle));

reinforcmentAreaExcessHeader = (2.0 * retirementZoneHalfWidth -


lengthRemovedFromPipe) * headerExcessThickness;

reinforcmentAreaExcessBranch = (2.0 *
reinforcementHeightOutsidePipeRun * branchExcessThickness) /
Math.Sin(headerAndBranchInfo.BranchAngle);

coverFillerWeldThroatThickness = 0.7 * branchNominalPipeThickness;

136 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

if (coverFillerWeldThroatThickness > (0.25 * 2.54 / 100))


{
coverFillerWeldThroatThickness = 0.25 * 2.54 / 100;
}

branchFilletWeldDimension = coverFillerWeldThroatThickness /
Math.Sin(Math.PI / 4);

reinforcmentHeight = reinforcingPadThickness +
branchFilletWeldDimension;

if (reinforcmentHeight <= reinforcementHeightOutsidePipeRun)


{
branchWeldReinforcementArea = 2.0 * (0.5 * branchFilletWeldDimension *
branchFilletWeldDimension);

halfThicknessReinforcementPad = reinforcingPadThickness;
}
else if (reinforcingPadThickness < reinforcementHeightOutsidePipeRun)
{
branchPadSizeAvaialble = reinforcementHeightOutsidePipeRun -
reinforcingPadThickness;

branchWeldReinforcementArea = 2.0 * (0.5 * branchPadSizeAvaialble *


branchPadSizeAvaialble);

halfThicknessReinforcementPad = reinforcingPadThickness;
}
else
{
branchWeldReinforcementArea = 0.0;
halfThicknessReinforcementPad = reinforcementHeightOutsidePipeRun;
}

headerReinforcementPadFillet = 0.5 * reinforcingPadThickness;

headerPadMinDimension = headerReinforcementPadFillet /
Math.Sin(Math.PI / 4);

headerWeldReinforcmentArea = 2.0 * (0.5 * headerPadMinDimension *


headerPadMinDimension);

reinforcingAreaBranchWeld = branchWeldReinforcementArea +
headerWeldReinforcmentArea;

if (headerJointQualityFactor > Math3d.DistanceTolerance)


{
headerAllowableStress = headerallowableStress *
headerJointQualityFactor / 100;
}
else

Intergraph Smart™ 3D .NET Programmer’s Guide 137


Reference Data Calculation Rules

{
headerAllowableStress = headerallowableStress;
}

if (branchJointQualityFactor > Math3d.DistanceTolerance)


{
branchAllowbleStress = branchAllowableStress *
branchJointQualityFactor / 100;
}
else
{
branchAllowbleStress = branchAllowableStress;
}

if (branchAllowbleStress < headerAllowableStress)


{
if (headerJointQualityFactor > Math3d.DistanceTolerance)
{
reinforcingPadAllowableStress = reinforcingPadAllowableStressinTension
* headerJointQualityFactor / 100;
}
else
{
reinforcingPadAllowableStress = headerAllowableStress;
}

allowableStressRatio = reinforcingPadAllowableStress /
headerAllowableStress;

if (allowableStressRatio > 1.0)


{
allowableStressRatio = 1.0;
}

reinforcingAreaBranchWeld = 0.0;
}
else
{
allowableStressRatio = 1.0;
}

reinfocementPadArea = (requiredReinforcementArea -
reinforcmentAreaExcessHeader - reinforcmentAreaExcessBranch -
reinforcingAreaBranchWeld) * allowableStressRatio;

if (headerMillTolerancePercent)
{
reinforcingPadCalculatedWidth = 0.5 * reinfocementPadArea /
(halfThicknessReinforcementPad * (1 - headerMillTolerance));
}
else
{

138 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

reinforcingPadCalculatedWidth = 0.5 * reinfocementPadArea /


(halfThicknessReinforcementPad - headerMillTolerance);
}

try
{
reinforcingPadMinimumWidth =
pipeSpec.GetMinimumReinforcingPadWidth(headerNPD, branchNPD,
headerAndBranchInfo.BranchAngle);

}
catch (Exception Ce)
{
throw Ce;
}

if (!headerAndBranchInfo.IsBranchReinforcementByUser)
{
if (reinforcingPadCalculatedWidth <= reinforcingPadMinimumWidth)
{
reinforcingPadhalfWidth = reinforcingPadCalculatedWidth + 0.5 *
branchOutDiameter + headerPadMinDimension;

if (reinforcingPadhalfWidth <= retirementZoneHalfWidth)


{
reinforcingPadWidth = reinforcingPadMinimumWidth;
//sufficient
}
else
{
//insufficient
message = "(reinforcingPadhalfWidth <= reinforcmentZoneHalfWidth) is
FALSE.";
throw new Utilities.RefDataInsufficientDataException(message);

}
}
else if (reinforcingPadCalculatedWidth > reinforcingPadMinimumWidth)
{
reinforcingPadhalfWidth = reinforcingPadCalculatedWidth + 0.5 *
branchOutDiameter + headerPadMinDimension;

if (reinforcingPadhalfWidth <= retirementZoneHalfWidth)


{
//using Convert.ToInt32 will round of the value to the nearest
integer. casting to int will round of to the base value without
decimal
reinforcingPadWidth = ((int)(reinforcingPadCalculatedWidth / (0.5 *
0.0254)) + 1) * (0.5 * 0.0254);
//round it to nearest 0.5"
//sufficient
}

Intergraph Smart™ 3D .NET Programmer’s Guide 139


Reference Data Calculation Rules

else
{
//insufficient
message = "(reinforcingPadhalfWidth <= reinforcmentZoneHalfWidth) is
FALSE.";
throw new Utilities.RefDataInsufficientDataException(message);

}
}
}
else
{
reinforcingPadWidth = branchreinforcementData.ReinforcingPadWidth;

if (reinforcingPadCalculatedWidth <= reinforcingPadWidth)


{
reinforcingPadhalfWidth = reinforcingPadCalculatedWidth + 0.5 *
branchOutDiameter + headerPadMinDimension;

if (reinforcingPadhalfWidth <= retirementZoneHalfWidth)


{
//sufficient
}
else
{
//insufficient
message = "(reinforcingPadhalfWidth <= reinforcmentZoneHalfWidth) is
FALSE.";
throw new Utilities.RefDataInsufficientDataException(message);
}
}
else
{
//insufficient
message = "(reinforcingPadCalculatedWidth <=
reinforcingPadCalculatedWidth) is FALSE.";
throw new Utilities.RefDataInsufficientDataException(message);
}
}

branchreinforcementData.ReinforcingPadThickness =
reinforcingPadThickness;
branchreinforcementData.ReinforcingPadWidth = reinforcingPadWidth;
}
catch (Exception Ce)
{
if (Ce is Utilities.RefDataInsufficientDataException)
{
//do nothing
}
else { throw Ce; }
}

140 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

return branchreinforcementData;

GetBranchReinforcementWeldData Method
/// <summary>
/// Returns the BranchReinforcementData object, which contains
/// ReinforcingWeldSize type data.</summary>
/// <param name="pipeSpec">Pipe specification class as
PipeSpec.</param>
/// <param name="headerPipeStock">Header pipe stock as
PipeStock.</param>
/// <param name="branchPipeStock">Branch pipe stock as
PipeStock.</param>
/// <param name="headerAndBranchInfo">Contains all the properties on
header
/// and branch pipe stock.</param>
public override BranchReinforcementData
GetBranchReinforcementWeldData(PipeSpec pipeSpec, PipeStock
headerPipeStock, PipeStock branchPipeStock, HeaderAndBranchInfo
headerAndBranchInfo)
{
if (pipeSpec == null)
{
throw new CmnArgumentNullException("pipeSpec");
}

if (headerPipeStock == null)
{
throw new CmnArgumentNullException("headerPipeStock");
}

if (branchPipeStock == null)
{
throw new CmnArgumentNullException("branchPipeStock");
}
//Default message for the error if anything else happened apart from
all the mentioned error codes
string message = "Error while calculating branch reinforcement";
CatalogOutfittingHelper pipingServices = new
CatalogOutfittingHelper();
BranchReinforcementData branchreinforcementData = new
BranchReinforcementData();
PreferredSchedule perferredSchedule = new PreferredSchedule();

#region Header and Branch Info Variables


NominalDiameter headerNPD = new NominalDiameter(), branchNPD = new
NominalDiameter();

Intergraph Smart™ 3D .NET Programmer’s Guide 141


Reference Data Calculation Rules

double headerOutsideDiameter = 0;
int headerMaterialsGrade = 0;
int headerMaterialsCategory = 0;
int headerSchedule = 0;
int headerSchedulePractice = 0;
int headerEndPrep = 0;
int headerEndStd = 0;
int headerPressureRating = 0;
int headerTerminationClass = 0;
int headerTerminationSubClass = 0;
int headerPipingPointBasis = 0;
int headerGeoIndStd = 0;

double branchOutsideDiameter = 0;
int branchMaterialsGrade = 0;
int branchMaterialsCategory = 0;
int branchSchedule = 0;
int branchSchedulePractice = 0;
int branchEndPrep = 0;
int branchEndStd = 0;
int branchPressureRating = 0;
int branchTerminationClass = 0;
int branchTerminationSubClass = 0;
int branchPipingPointBasis = 0;
int branchGeoIndStd = 0;
#endregion

#region Branch PipeStock variable

//internal design gauge pressure for branch


double branchPressureGauge = 0;
//branch outside diameter
double branchOutDiameter = 0;
//allowable stress in tension for the branch
double branchAllowableStress = 0;
//joint quality factor for the branch
double branchJointQualityFactor = 0;
//coefficient for branch material
double branchMaterialCoefficient = 0;
//calculated branch thickness
double branchCalcThickness = 0;
//mill tolerance
double branchMillTolerance = 0;
//is mill tolerance percentage
bool branchMilltolerancePercentage = false;
//low end of the wall thickness range
double branchLowThicknessRange = 0;
//high end of the wall thickness range
double branchHighThicknessRange = 0;
//thread thickness for threaded pipe, if applicable, from the
Thickness Data rule
double branchThreadThickness = 0;

142 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

//minimum branch thickness from thickness data rule


double branchMinThickness = 0;
//retirement thickness from the thickness data rule
double branchRetirementThickness = 0;
//uncorroded branch thickness
double branchUncorrodedThickness = 0;
//minimum calculated branch thickness
double branchMinCalThickness = 0;
//required branch thickness
double branchRequiredThickness = 0;
//branch corrosion allowance from the Corrosion Allowance rule
double branchCorrosionAllowance = 0;
//nominal branch pipe thickness
double branchNominalPipeThickness = 0;
//minimum branch wall thickness permissible under purchase
specification
double branchMinWallThickness = 0;
//branch mill tolerance
double branchMillToleranceVal = 0;
//required minimum wall thickness for branch
double branchRequiredWallThickness = 0;
//additional thickness
double branchAdditionalThickness = 0;
//excess branch thickness
double branchExcessThickness = 0;
//branch pressure design thickness
double branchPrseeureDesignThickness = 0;

#endregion

#region Header PipeStock Variables

//internal design gauge pressure for header


double headerPressureGauge = 0;
//header outside diameter
double headerOutDiameter = 0;
//allowable stress in tension for the header
double headerallowableStress = 0;
//joint quality factor for the header
double headerJointQualityFactor = 0;
//coefficeient for header material
double headerMaterialCoefficient = 0;
//calculated header thickness
double headerCalcThickness = 0;
//mill tolerance
double headerMillTolerance = 0.0;
//is mill tolerance percentage
bool headerMillTolerancePercent = false;
//low end of the wall thickness range
double headerlowThicknessRange = 0.0;
//high end of the wall thickness range
double headerHighThicknessRange = 0.0;

Intergraph Smart™ 3D .NET Programmer’s Guide 143


Reference Data Calculation Rules

//thread thickness for threaded pipe, if applicable, from the


Thickness Data rule
double headerThreadThickness = 0;
//minimum header thickness from thickness data rule
double headerMinThickness = 0;
//retirement thickness from the thickness data rule
double headerRetirementThickness = 0;
//uncorroded header thickness
double headerUncorrodedThickness = 0;
//minimum calculated header thickness
double headerMinCalThickness = 0;
//required header thickness
double headerRequiredThickness = 0;
//header corrosion allowance from the Corrosion Allowance rule
double headerCorrosionAllownace = 0;
//nominal header pipe thickness
double headernominalPipeThickness = 0;
//minimum header wall thickness permissible under purchase
specification
double headerMinPermissibleWallThickness = 0;
//header mill tolerance
double headerMillToleranceVal = 0;
//required minimum wall thickness for header
double headerMinWallThickness = 0;
//additional thickness
double headerAdditionalThickness = 0;
//excess header thickness
double headerExcessThickness = 0;
//header pressure design thickness
double headerPressureDesignThickness = 0;
#endregion

#region Weld Reinforcement Variable

//reinforcement calculation

//minimum reinforcement thickness


double minReinforcementThickness = 0;
//height of reinforcement zone outside of pipe run
double reinforcementHeightPipeRun = 0;
//effective length removed from pipe at branch
double pipeLengthRemoved = 0;
//half width of reinforcement zone
double reinforcmentZoneHalfWidth = 0;
//required reinforcement area
double reinforcementAreaRequired = 0;
//reinforcement area resulting from the excess thickness in the header
pipe wall
double reinforcmentAreaExcessHeader = 0;
//reinforcement area resulting from the excess thickness in the branch
pipe wall
double reinforcmentAreaExcessBranch = 0;

144 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

//reinforcement area resulting from the branch welds


double reinforcingAreaBranchWeld = 0;
//total available reinforcement area
double totalReinforcementArea = 0;
//minimum leg dimension of branch fillet weld
double branchFilletWeldDimension = 0;
//throat thickness of cover fillet weld
double coverFillerWeldThroatThickness = 0;

//*********************************************
//branch reinforcement for reinforcing welds

//minimum weld size from the reinforcing weld data rule


double minimumWeldSize = 0;
//minimum size of reinforcing fillet weld on branch
double reinforcingFilletWeldSize = 0;
//minimum leg dimension of branch fillet weld
double minLegDimension = 0;

#endregion

try
{

IPipeComponent pipeComponent;
pipeComponent = headerPipeStock;

Part headerpart = (Part)pipeComponent;


ReadOnlyCollection<BusinessObject> headerports =
headerpart.PortDefinitions;

//for the header pipe stock


headerNPD = pipeComponent.PrimaryNPD;
headerMaterialsGrade = pipeComponent.MaterialGrade;
headerMaterialsCategory = pipeComponent.MaterialCategory;
headerGeoIndStd = pipeComponent.GeometricIndustryStandard;

PipePortDef headerPipePortDef = (PipePortDef)headerports.ElementAt(1);

headerOutsideDiameter = headerPipePortDef.PipingOutsideDiameter;
headerEndPrep = headerPipePortDef.EndPreparation;
headerEndStd = headerPipePortDef.EndStandard;
headerPressureRating = headerPipePortDef.PressureRating;
headerSchedule = headerPipePortDef.ScheduleThickness;
headerSchedulePractice = headerPipePortDef.SchedulePractice;
headerTerminationClass = headerPipePortDef.TerminationClass;
headerTerminationSubClass = headerPipePortDef.TerminationSubClass; ;
headerPipingPointBasis = headerPipePortDef.PipingPointBasis;

Intergraph Smart™ 3D .NET Programmer’s Guide 145


Reference Data Calculation Rules

pipeComponent = branchPipeStock;
Part branchpart = (Part)pipeComponent;

ReadOnlyCollection<BusinessObject> branchports =
branchpart.PortDefinitions;

//for the branch pipe stock


branchNPD = pipeComponent.PrimaryNPD;
branchMaterialsGrade = pipeComponent.MaterialGrade;
branchMaterialsCategory = pipeComponent.MaterialCategory;
branchGeoIndStd = pipeComponent.GeometricIndustryStandard;

PipePortDef branchPipePortDef = (PipePortDef)branchports.ElementAt(1);

branchOutsideDiameter = branchPipePortDef.PipingOutsideDiameter;
branchEndPrep = branchPipePortDef.EndPreparation;
branchEndStd = branchPipePortDef.EndStandard;
branchPressureRating = branchPipePortDef.PressureRating;
branchSchedule = branchPipePortDef.ScheduleThickness;
branchSchedulePractice = branchPipePortDef.SchedulePractice;
branchTerminationClass = branchPipePortDef.TerminationClass;
branchTerminationSubClass = branchPipePortDef.TerminationSubClass; ;
branchPipingPointBasis = branchPipePortDef.PipingPointBasis;

headerOutDiameter = headerOutsideDiameter;

try
{
//Get the header Joint Quality factor
headerJointQualityFactor = pipeSpec.GetJointQualityFactor(headerNPD,
headerAndBranchInfo.HeaderCommodityOption);
}
catch (Exception Ce)
{
throw Ce;
}

//get the data set of materials data rule


DataSet dataset = null;

try
{
dataset = pipingServices.GetMaterialsData(pipeSpec,
headerMaterialsGrade, headerAndBranchInfo.HeaderTemperature);
}
catch (Exception)
{
throw new Utilities.RefDataInsufficientDataException(message);
}

146 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

bool isInterpolatedSY = false;

if (dataset != null)
isInterpolatedSY =
Utilities.GetInterpolatedSYFromMaterialsDataRule(dataset,
headerAndBranchInfo.HeaderTemperature, ref headerallowableStress, ref
headerMaterialCoefficient);

if (isInterpolatedSY == false)
{
//insufficient
message = "MaterialsDataRule does NOT address the calculated header
thickness.";
throw new Utilities.RefDataInsufficientDataException(message);
}

Utilities.ConvertPressureOrStressToGageUnits(headerAndBranchInfo.Heade
rPressure, ref headerPressureGauge);

headerCalcThickness = (headerPressureGauge * headerOutDiameter) / (2.0


* (headerallowableStress * (headerJointQualityFactor / 100) +
headerPressureGauge * headerMaterialCoefficient));

int counter1 = 1;
//Add here data set calculation
do
{
headerlowThicknessRange = Utilities.GetRecordsFromDataset(dataset,
"WallThicknessFrom");
headerHighThicknessRange = Utilities.GetRecordsFromDataset(dataset,
"WallThicknessTo");

if ((headerCalcThickness < (headerOutDiameter / 6.0)) &&


((Math.Abs(headerlowThicknessRange - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance || (headerCalcThickness >=
headerlowThicknessRange)) && (Math.Abs(headerHighThicknessRange -
Utilities.DOUBLEZERO) <= Math3d.DistanceTolerance ||
(headerCalcThickness <= headerHighThicknessRange))))
{
headerMillTolerance = Utilities.GetRecordsFromDataset(dataset,
"MillTolerance");
if (Math.Abs(headerMillTolerance - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance)
{
headerMillTolerance = Utilities.GetRecordsFromDataset(dataset,
"MillTolerancePercentage");
headerMillTolerance = headerMillTolerance / 100;
if (Math.Abs(headerMillTolerance - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance)
{
throw new CmnException("Error while calculating mill tolerance",
(int)RefDataRuleErrorType.E_FAIL);

Intergraph Smart™ 3D .NET Programmer’s Guide 147


Reference Data Calculation Rules

}
headerMillTolerancePercent = true;
}
else
{
headerMillTolerancePercent = false;
}
break;
}

counter1++;
} while (counter1 <= dataset.Tables[0].Rows.Count);

if (Math.Abs(headerMillTolerance - Utilities.DOUBLEZERO) <=


Math3d.DistanceTolerance)
{
//insufficient
message = "MaterialsDataRule does NOT address the calculated header
thickness.";
throw new Utilities.RefDataInsufficientDataException(message);
}
//rsMaterialsDataRule.Close
///////////////////////////////////////////////////////////

try
{
pipeSpec.GetThicknessData(headerNPD, out headerMinThickness, out
headerRetirementThickness, out headerThreadThickness, ref
perferredSchedule);
}
catch (Exception Ce)
{
throw Ce;
}

if (headerCalcThickness > headerRetirementThickness)


{
headerUncorrodedThickness = headerCalcThickness;
}
else
{
headerUncorrodedThickness = headerRetirementThickness;
}
try
{
headerCorrosionAllownace =
pipeSpec.CorrosionAllowance(headerMaterialsCategory,
headerAndBranchInfo.HeaderFluidCode);
}
catch (Exception Ce)
{
throw Ce;

148 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

}
if (headerMillTolerancePercent)
{
headerMinCalThickness = (headerUncorrodedThickness +
headerCorrosionAllownace + headerThreadThickness) / (1 -
headerMillTolerance);
}
else
{
headerMinCalThickness = headerUncorrodedThickness +
headerCorrosionAllownace + headerThreadThickness +
headerMillTolerance;
}

if ((headerMinCalThickness > headerMinThickness))


{
headerRequiredThickness = headerMinCalThickness;
}
else
{
headerRequiredThickness = headerMinThickness;
}

PipePortProperties pipePortProperties = new PipePortProperties();

pipePortProperties.Schedule = headerSchedule;
pipePortProperties.EndPreparation = headerEndPrep;
pipePortProperties.EndStandard = headerEndStd;
pipePortProperties.Npd = headerNPD.Size;
pipePortProperties.NpdUnitType = headerNPD.Units;
pipePortProperties.PressureRating = headerPressureRating;
pipePortProperties.PipingPointBasis = headerPipingPointBasis;
pipePortProperties.GeometricIndustryStd = headerGeoIndStd;
pipePortProperties.LiningMaterial = 1;

try
{
headernominalPipeThickness =
pipeSpec.GetNominalPipeThickness(pipePortProperties);
}
catch (Exception Ce)
{
throw Ce;
}
if (headerRequiredThickness < headernominalPipeThickness)
{
//required header thickness is sufficient for branch reinforcement
calc
}
else
{
//insufficient

Intergraph Smart™ 3D .NET Programmer’s Guide 149


Reference Data Calculation Rules

message = "(headerRequiredThickness < headernominalPipeThickness) is


FALSE.";
throw new Utilities.RefDataInsufficientDataException(message);
}

if (headerMillTolerancePercent)
{
headerMillToleranceVal = headernominalPipeThickness *
headerMillTolerance;
}
else
{
headerMillToleranceVal = headerMillTolerance;
}

headerAdditionalThickness = headerMillToleranceVal +
headerCorrosionAllownace;

if ((headerMinCalThickness >= headerMinThickness &


headerRetirementThickness >= headerCalcThickness))
{
headerMinPermissibleWallThickness = headernominalPipeThickness -
headerMillToleranceVal;
headerMinWallThickness = headerRequiredThickness;
headerExcessThickness = headernominalPipeThickness -
headerRequiredThickness;
headerPressureDesignThickness = headerRequiredThickness -
headerMillToleranceVal - headerCorrosionAllownace;
}
else
{
headerMinPermissibleWallThickness = headernominalPipeThickness -
headerMillToleranceVal;
headerMinWallThickness = headerUncorrodedThickness +
headerMillToleranceVal + headerCorrosionAllownace;
headerExcessThickness = headernominalPipeThickness -
headerMillToleranceVal - headerCorrosionAllownace -
headerUncorrodedThickness;
headerPressureDesignThickness = headerUncorrodedThickness;
}

branchOutDiameter = branchOutsideDiameter;

try
{
branchJointQualityFactor = pipeSpec.GetJointQualityFactor(branchNPD,
headerAndBranchInfo.BranchCommodityOption);
}
catch (Exception Ce)
{
throw Ce;
}

150 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

try
{
dataset = pipingServices.GetMaterialsData(pipeSpec,
branchMaterialsGrade, headerAndBranchInfo.BranchTemperature);

}
catch (Exception Ce)
{
throw Ce;
}

isInterpolatedSY = false;

if (dataset != null)
isInterpolatedSY =
Utilities.GetInterpolatedSYFromMaterialsDataRule(dataset,
headerAndBranchInfo.BranchTemperature, ref branchAllowableStress, ref
branchMaterialCoefficient);

if (isInterpolatedSY == false)
{
//insufficient
message = "MaterialsDataRule does NOT address the calculated branch
thickness.";
throw new Utilities.RefDataInsufficientDataException(message);
}

Utilities.ConvertPressureOrStressToGageUnits(headerAndBranchInfo.Branc
hPressure, ref branchPressureGauge);

branchCalcThickness = (branchPressureGauge * branchOutDiameter) / (2.0


* (branchAllowableStress * (branchJointQualityFactor / 100) +
branchPressureGauge * branchMaterialCoefficient));

//////////////////////////////////////////////////////////////////////
//

int count1 = 1;
//Add here data set calculation
do
{
branchLowThicknessRange = Utilities.GetRecordsFromDataset(dataset,
"WallThicknessFrom");
branchHighThicknessRange = Utilities.GetRecordsFromDataset(dataset,
"WallThicknessTo");

if ((headerCalcThickness < (headerOutDiameter / 6.0)) &&


((Math.Abs(branchLowThicknessRange - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance || (headerCalcThickness >=
branchLowThicknessRange)) && (Math.Abs(branchHighThicknessRange -

Intergraph Smart™ 3D .NET Programmer’s Guide 151


Reference Data Calculation Rules

Utilities.DOUBLEZERO) <= Math3d.DistanceTolerance ||


(branchCalcThickness <= branchHighThicknessRange))))
{
branchMillTolerance = Utilities.GetRecordsFromDataset(dataset,
"MillTolerance");
if (Math.Abs(branchMillTolerance - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance)
{
branchMillTolerance = Utilities.GetRecordsFromDataset(dataset,
"MillTolerancePercentage");
branchMillTolerance = branchMillTolerance / 100;
if (Math.Abs(branchMillTolerance - Utilities.DOUBLEZERO) <=
Math3d.DistanceTolerance)
{
//this.ErrorStatus = new
RefDataRuleErrorStatus(RefDataRuleErrorType.E_FAIL, "Error while
calculating mill tolerance");
throw new CmnException("Error while calculating mill tolerance",
(int)RefDataRuleErrorType.E_FAIL);
}
branchMilltolerancePercentage = true;
}
else
{
branchMilltolerancePercentage = false;
}
break;
}

count1++;
} while (count1 <= dataset.Tables[0].Rows.Count);

if (Math.Abs(branchMillTolerance - Utilities.DOUBLEZERO) <=


Math3d.DistanceTolerance)
{
//insufficient
message = "MaterialsDataRule does NOT address the calculated branch
thickness.";
throw new Utilities.RefDataInsufficientDataException(message);
}

////////////do while
ends//////////////////////////////////////////////////
try
{
pipeSpec.GetThicknessData(branchNPD, out branchMinThickness, out
branchRetirementThickness, out branchThreadThickness, ref
perferredSchedule);
}
catch (Exception Ce)
{
throw Ce;

152 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

if ((branchCalcThickness > branchRetirementThickness))


{
branchUncorrodedThickness = branchCalcThickness;
}
else
{
branchUncorrodedThickness = branchRetirementThickness;
}

pipePortProperties = new PipePortProperties();

pipePortProperties.EndPreparation = branchEndPrep;
pipePortProperties.EndStandard = branchEndStd;
pipePortProperties.Npd = branchNPD.Size;
pipePortProperties.NpdUnitType = branchNPD.Units;
pipePortProperties.PressureRating = branchPressureRating;
pipePortProperties.Schedule = branchSchedule;
pipePortProperties.PipingPointBasis = branchPipingPointBasis;
pipePortProperties.GeometricIndustryStd = branchGeoIndStd;
pipePortProperties.LiningMaterial = 1;

try
{
branchNominalPipeThickness =
pipeSpec.GetNominalPipeThickness(pipePortProperties);

}
catch (Exception Ce)
{
throw Ce;
}

if (branchMilltolerancePercentage)
{
branchMillToleranceVal = branchNominalPipeThickness *
branchMillTolerance;
}
else
{
branchMillToleranceVal = branchMillTolerance;
}
try
{
branchCorrosionAllowance =
pipeSpec.CorrosionAllowance(branchMaterialsCategory,
headerAndBranchInfo.BranchFluidCode);

}
catch (Exception Ce)
{

Intergraph Smart™ 3D .NET Programmer’s Guide 153


Reference Data Calculation Rules

throw Ce;
}

if (branchMilltolerancePercentage)
{
branchMinCalThickness = (branchUncorrodedThickness +
branchCorrosionAllowance + branchThreadThickness) / (1 -
branchMillTolerance);
}
else
{
branchMinCalThickness = branchUncorrodedThickness +
branchCorrosionAllowance + branchThreadThickness +
branchMillTolerance;
}

if ((branchMinCalThickness > branchMinThickness))


{
branchRequiredThickness = branchMinCalThickness;
}
else
{
branchRequiredThickness = branchMinThickness;
}

if (branchRequiredThickness < branchNominalPipeThickness)


{
//required branch thickness is sufficient for branch reinforcement
calc
}
else
{
//insufficient
message = "(branchRequiredThickness < branchNominalPipeThickness) is
FALSE.";
throw new Utilities.RefDataInsufficientDataException(message);
}

branchAdditionalThickness = branchMillToleranceVal +
branchCorrosionAllowance;

if ((branchMinCalThickness >= branchMinThickness &


branchRetirementThickness >= branchCalcThickness))
{
branchMinWallThickness = branchNominalPipeThickness -
branchMillToleranceVal;
branchRequiredWallThickness = branchRequiredThickness;
branchExcessThickness = branchNominalPipeThickness -
branchRequiredThickness;
branchPrseeureDesignThickness = branchRequiredThickness -
branchMillToleranceVal - branchCorrosionAllowance;
}

154 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

else
{
branchMinWallThickness = branchNominalPipeThickness -
branchMillToleranceVal;
branchRequiredWallThickness = branchUncorrodedThickness +
branchMillToleranceVal + branchCorrosionAllowance;
branchExcessThickness = branchNominalPipeThickness -
branchMillToleranceVal - branchCorrosionAllowance -
branchUncorrodedThickness;
branchPrseeureDesignThickness = branchUncorrodedThickness;
}

if (branchPressureGauge < headerPressureGauge)


{
branchExcessThickness = 0.0;
}

minReinforcementThickness = 0.0;

reinforcementHeightPipeRun = 2.5 * (branchPrseeureDesignThickness -


branchAdditionalThickness) + minReinforcementThickness;

pipeLengthRemoved = (branchOutDiameter - 2.0 *


branchNominalPipeThickness) /
Math.Sin(headerAndBranchInfo.BranchAngle);

reinforcmentZoneHalfWidth = branchPrseeureDesignThickness -
branchAdditionalThickness + headerMinPermissibleWallThickness +
pipeLengthRemoved / 2.0;

if (reinforcmentZoneHalfWidth < pipeLengthRemoved)


{
reinforcmentZoneHalfWidth = pipeLengthRemoved;
}

if (reinforcmentZoneHalfWidth > headerOutDiameter)


{
reinforcmentZoneHalfWidth = headerOutDiameter;
}

reinforcementAreaRequired = 1.07 * headerMinWallThickness *


pipeLengthRemoved * (2.0 - Math.Sin(headerAndBranchInfo.BranchAngle));

reinforcmentAreaExcessHeader = (2.0 * reinforcmentZoneHalfWidth -


pipeLengthRemoved) * headerExcessThickness;

reinforcmentAreaExcessBranch = (2.0 * reinforcementHeightPipeRun *


branchExcessThickness) / Math.Sin(headerAndBranchInfo.BranchAngle);

if (headerAndBranchInfo.IsBranchReinforcementByUser)
{

Intergraph Smart™ 3D .NET Programmer’s Guide 155


Reference Data Calculation Rules

minimumWeldSize = branchreinforcementData.ReinforcingWeldSize;
}
else
{
pipeSpec.GetReinforcingWeldSize(headerNPD, branchNPD,
headerAndBranchInfo.BranchAngle, out minimumWeldSize);
}

coverFillerWeldThroatThickness = minimumWeldSize;

branchFilletWeldDimension = coverFillerWeldThroatThickness /
Math.Sin(Math.PI / 4);

reinforcingAreaBranchWeld = branchFilletWeldDimension *
branchFilletWeldDimension;

totalReinforcementArea = reinforcmentAreaExcessHeader +
reinforcmentAreaExcessBranch + reinforcingAreaBranchWeld;

if ((totalReinforcementArea >= reinforcmentAreaExcessHeader))


{
reinforcingFilletWeldSize = 0.7 * branchNominalPipeThickness;

if (reinforcingFilletWeldSize > (0.25 * 2.54 / 100))


{
reinforcingFilletWeldSize = 0.25 * 2.54 / 100;
}

minLegDimension = reinforcingFilletWeldSize / Math.Sin(Math.PI / 4);

if (minimumWeldSize >= minLegDimension)


{
//branch reinforcement is sufficient
}
else
{
//branch reinforcement is insufficient
message = "(minimumWeldSize >= minLegDimension) is FALSE.";
throw new Utilities.RefDataInsufficientDataException(message);
}
}
else
{
//branch reinforcement is insufficient
message = "(totalReinforcementArea >= reinforcmentAreaExcessHeader) is
FALSE.";
throw new Utilities.RefDataInsufficientDataException(message);
}

branchreinforcementData.ReinforcingWeldSize = minimumWeldSize;
}
catch (Exception Ce)

156 Intergraph Smart™ 3D .NET Programmer’s Guide


Reference Data Calculation Rules

{
if (Ce is Utilities.RefDataInsufficientDataException)
{
//do nothing
}
else { throw Ce; }

}
return branchreinforcementData;

Intergraph Smart™ 3D .NET Programmer’s Guide 157


Appendix A: Usage Caveats

Appendix A: Usage Caveats


Appendix lists known caveats when using the CommonApp API.

158 Intergraph Smart™ 3D .NET Programmer’s Guide


Appendix A: Usage Caveats

SP3DConnection.DatabaseID Works Only for the


Active Connection
Note: This affects 2009.1 and all previous software releases.
The DatabaseID property defined on the SP3DConnection class returns the correct value only
for the Active Connection. This restriction also applies to all classes that derive from
SP3DConnection, including:
• PlantConnection
• Site
• Model
• Catalog
• Report
• Reference
For example, the following does not provide correct results:
For Each plantt As Plant In
MiddleServiceProvider.SiteMgr.ActiveSite.Plants
Msgbox plantt.PlantModel.DatabaseID.ToUpper
Next plantt

Intergraph Smart™ 3D .NET Programmer’s Guide 159


Index

Index
.NET architecture, 14 types, 21
appendix writing graphic commands, 34
usage caveats, 93 writing modal commands, 28
creating .NET symbols, 75 writing step commands, 38
bulkloading, 79 creating naming rules, 45
bulkloading piping symbols, 79 configuration, 55
defining ports, 77 deployment, 55
definition, 78 GenericNamingRules, 55
deploying symbols, 78 name rule project, 48
placing a piping symbol, 80 NameRuleBase, 46
understanding the geometry, 76 writing a name rule, 50
creating advanced .NET symbols, 81 examples
custom foul check, 83 PartSubImpact, 63
custom mirror, 84 SAPBase, 62
custom weight and COG, 81 namespaces and assemblies, 17
dynamic outputs, 81 3D assemblies, 19
origin and orientation, 82 3D namespaces, 18
property management, 85 assemblies, 19
creating commands namespaces, 18
.NET, 20 preface, 6
.NET methods and properties, 21 references, 9
.NET project, 26 resources, 9
BaseGraphicCommand, 34 Smart 3D architecture
BaseModalCommand, 29 business objects, 10
BaseRibbonBarControl, 43 client, 10
BaseStepCommand, 38 metadata, 10
client level services, 22 middle, 10
ClientServiceProvider, 22 server, 10
command assistants, 25 Smart 3D architecture
committing transactions, 25 three-tier, 10
graphic command example, 35 stand-alone applications, 57
graphic commands, 23 available services, 57
IJCommand2 COM interface, 21 PartSubImpact example, 63
menu handler, 21 runtime and building, 63
modal commands, 23 SAPBase example, 62
modal example, 30 services not available, 58
object-based, 21 setting system PATH, 65
preventing database corruption, 25 settings for C#, 64
ribbon bars, 43 settings for VB, 65
step command example, 40 writing, 58
step commands, 24 writing .NET symbols, 78
terminating commands, 25

160 Intergraph Smart™ 3D .NET Programmer’s Guide

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy