跳转至

组件开发流程

节点组件开发流程

  • 节点组件有主零件和次零件,主零件有且只有1个,次零件需要设置最小个数和最大个数(必须要大于等于1),类型为ConnectionComponent
    //设置次零件的最大最小个数
    public override int RequiredSubsMaxCount => 2; 
    public override int RequiredSubsMinCount => 1; 
    

不创建自定义Controller的方式 示例代码:Example_ConnectionComponent1

  • 从节点组件中得到主次零件和主次零件的包围面(次零件可能有多个,示例为两个),组件创建时,通过零件之间的位置关系决定在哪里创建
    public bool Initialize(ConnectionComponent comp)
    {
        if (comp == null)
            return false;
        Beam mainPart = comp.Main as Beam;
        Beam subPart1 = comp.Subs.Length > 0 ? comp.Subs.First<TFObject>() as Beam : null;
        Beam subPart2 = comp.Subs.Length > 1 ? comp.Subs[1] as Beam : null;
        if (mainPart == null || subPart1 == null)
            return false;
        m_comp = comp;
        m_mainPart = mainPart;
        m_subPart1 = subPart1;
        m_subPart2 = subPart2;
        m_mainPlanes = BeamPlanes.CreateFromBeam(m_mainPart);
        m_subPlanes1 = BeamPlanes.CreateFromBeam(m_subPart1);
        m_subPlanes2 = BeamPlanes.CreateFromBeam(m_subPart2);
        ParsePlanes();
        return true;
    }
    

创建自定义Controller的方式 示例代码:Example_ConnectionComponent2

  • 相较于不创建自定义的方式,该方式可选取创建点,设置图标位置等(有且只有一个主零件,次零件数大于等于一)
    public override bool OnInstanceCreate(ComponentBase instObj, CompCreateInfo cinfo)
    {
        if (cinfo == null || cinfo.UserData == null) return false ;
        //处理相对坐标
        var data = cinfo.UserData;
        //设置组件图标位置
        var ctrlPos0 = data.GetVec3(CreateStairController.COMP_TAG_POS);
        instObj.WorldTagPos = ctrlPos0;
        return base.OnInstanceCreate(instObj, cinfo);
    }
    
  • 在CreateStairController类中自定义创建的主次零件和创建位置等
    private void SwitchStep0()
    {
        this.BeginPick(Define.PICK_PART, Define.PICK_PART, Define.PICK_NONE);
        this.SetTip("创建组件:选择主零件");
        this.SetCursor(LoongCAD.STC.Define.MouseCursor.CURSOR_HAND);
        m_state = 0;
        m_IdComp0 = 0;
        m_IdComp1 = 0;
    }
    public override void OnMouseClick(MouseButtons button, int x, int y, bool ctrl, bool alt, bool shift) {
    if (m_state == 0) {
        var ids = this.GetPickedObjects(ctrl, alt, shift);
        if (ids != null && ids.Length > 0) {
        SwitchStep1(ids[0]);
        }
    }
    else if (m_state == 1) {
        var ids = this.GetPickedObjects(ctrl, alt, shift);
        if (ids != null && ids.Length > 0) {
        SwitchStep2(ids[0]);
        }
    }
        base.OnMouseClick(button, x, y, ctrl, alt, shift);
    }
    public override bool IsObjectFocused(long id) {
    if (id == m_IdComp0 || id == m_IdComp1) { return true; }
    return false;
    }
    public override void OnDeactive()
    {
        m_state = 0;
        m_IdComp0 = 0;
        m_IdComp1 = 0;
        this.CreateInfo.UserData = null;
        base.OnDeactive();
    }
    public override void OnSnapPoint(Vec3 pt) {
    base.OnSnapPoint(pt);
    if (m_state == 2) {
        this.CreateInfo.MainId = m_IdComp0;
        this.CreateInfo.SubIds.Add(m_IdComp1);
        this.CreateInfo.UserData = new DObject();
        this.CreateInfo.UserData[COMP_TAG_POS] = pt;
        m_state = 0;
        this.CompleteCreation();
        this.Quit();
        }
    }
    public override void OnSnapRevert(){
        if(m_state == 1) {
            SwitchStep0();
        } else if (m_state == 2) {
            SwitchStep1(m_IdComp0);
            }
            base.OnSnapRevert();
    }
    

细部组件开发流程

  • 细部和节点的区别在于,细部有且只有一个零件,且一般要选取创建组件的位置,类型为DetailComponent

不创建自定义Controller的方式 示例代码:Example_DetailComponent1

  • 执行时需要将类型换为细部类型,可以直接获取节点的控制点来获取细部创建的位置,其他同节点组件
    public override bool OnInstanceRun(ComponentBase compInst, long defaultId) 
    {
        if (compInst == null || !(compInst is DetailComponent))
        return false;
    
        // 1. 获取组件实例的属性
        DObject compProps = compInst.UIProps;
        if (compProps == null) {
        compProps = new DObject();
        }
        // 2. 初始化参数处理器,此过程包含以下操作:
        // * 初始化参数值
        // * 初始化参数空值表
        // * 初始化参数内置默认值表
        // * 组合参数默认值
        ParamsHandler paramsHandler = new ParamsHandler();
        paramsHandler.ParamValues = compProps;
        paramsHandler.InitializeDefaultValues(this.GetDefaultsData(defaultId));
        // 3. 初始化组件上下文,此过程执行以下操作
        var compContext = ComponentInstanceContext.CreateInstance(compInst as DetailComponent, paramsHandler);
        if (compContext == null)
        return false;
        // 4. 执行组件的每一个功能
        {
        LiftingHandler graphicHandler = new LiftingHandler(compContext, paramsHandler);
        if (!graphicHandler.Execute()) return false;
        }
        return true;
    }
    

创建自定义Controller的方式 示例代码:Example_DetailComponent2

  • 和节点自定义Controller方式大致相同,只需要将CustomCompCreateController替换为DetailCompCreateController

自定义组件开发流程 示例代码:Example_UserDefine

创建自定义Controller的方式

  • 自定义组件,只有自定义Controller方式,节点和细部也都属于自定义组件的其中一种,自定义组件可以决定要任意几个零件(可以为0),和创建点,在CreateStairController中自定义需要几个零件和点(代码和节点自定义Controller结构相同)
    public override bool OnInstanceCreate(ComponentBase instObj, CompCreateInfo cinfo) 
    {
        //处理相对坐标
        var data = cinfo.UserData;
        //设置组件图标位置
        var ctrlPos0 = data.GetVec3(CreateStairController.CTRL_POS_0);
        var ctrlPos1 = data.GetVec3(CreateStairController.CTRL_POS_1);
        instObj.ObjectWorldMatrix = new Mat43(Vec3.AXIS_X, Vec3.AXIS_Y, Vec3.AXIS_Z, ctrlPos0);
        instObj.SetWorldCtrlPoints(new[] { ctrlPos0, ctrlPos1 });
        return base.OnInstanceCreate(instObj, cinfo);
    }
    

组件开发部件 示例代码:Example_ConnectionComponent1

创建直梁

创建直梁一般分为四步:

  1. 设置直梁创建所需要的两个控制点,即确定直梁的位置(直梁高度也是控制点决定)。
  2. 设置直梁的截面,一般有H,I,L等截面,设置截面一般有两种方式,1.通过字符串拼接来设置截面,一般是”截面类型”+”截面厚度”+”截面宽度”,2.直接通过UI界面获取对应的截面
    //拼接
    string profile = "PL" + Thickness.ToString() + "*" + width.ToString();
    //UI界面获取
    private BeamProperties beam_profile = new BeamProperties();
    beam_profile.SetProps(m_paramsHandler.GetDObjectValue(ParamNames.PROFILE));
    
  3. 创建直梁,并设置直梁的工作坐标系,名称编号等,创建直梁共需四个参数,第一个为对象用途key,第二个为直梁的截面,第三和第四为直梁的两个控制点
    beam_part = m_context.Comp.GetOrCreateSteelBeam("beam_part",profile,point1,point2);
    
  4. 设置直梁的其他参数,和工作坐标系等(设置完所有参数一定要Refresh)
    private void ApplyBeamParameters(SteelBeam Beam, BeamProperties BeamProps)
    {
        if (Beam is null)
            return;
        BeamProps.ApplyToPart(Beam);
        Vec3 y = -m_context.SubPlane_front.Normal.Normalize();
        Vec3 z = (point1 - point2).Normalize();
        Vec3 x = y.Cross(z);
        Beam.WorkAxis = new Mat43(x, y, z, Vec3.ZERO);
        Beam.HorizonOffsetSide = Define.ObjectSide.SIDE_RIGHT;
        Beam.HorizonOffset = 0;
        Beam.RotationSide = Define.ObjectSide.SIDE_FRONT;
        Beam.Rotation = 0;
        Beam.VertOffsetSide = Define.ObjectSide.SIDE_MIDDLE;
        Beam.VerticalOffset = 0;
        Beam.Refresh();
    }
    

创建多边形板

创建多边形板一般分为三步:

  1. 设置直梁创建所需要的四个控制点或者六个包围面,即确定多边形板的位置(多边形板的高和截面的高由控制点或面确定)。
  2. 多边形板都是PL类型的截面,故不用设置截面。创建多边形板有两种方式。1.通过控制点来创建,创建共需四个参数,第一个为对象用途key,用于下一次执行时索引复用(创建的所有零件,key都不能重复,必须要唯一),第二个为多边形板的控制点(控制点要有顺序),第三个为多边形板的厚度,第四个为多边形板位于控制点形成的面的中间还是前面还是后面。2.通过面来创建,创建共需要四个参数,第一个为对象用途key,第二个为多边形板的顶面,第三个为多边形板的底面,第四个为多边形板的侧面(要有顺序)
    //通过点来创建
    plate = m_context.Comp.GetOrCreateSteelPlate("PLATE", points,Thickness, Define.ObjectSideSIDE_FRONT);
    //通过面来创建
    plate = m_context.Comp.GetOrCreateSteelPlate("PLATE", top_plane,bottom_plane, side_plane);
    
  3. 一般多边形板都要设置折角,将要设置折角的控制点存入ChamferCtrlPoint中,再设置折角类型和折角大小
    ChamferCtrlPoint[] chamferCtrlPoint = new ChamferCtrlPoint[count];
    chamferCtrlPoint[i].CutType = Define.CornerCutType.CORNER_CUT_ROUND;
    chamferCtrlPoint[i].CutR = x;
    chamferCtrlPoint[i].Refresh();
    

创建螺栓

创建螺栓一般分为两步:

  1. 初始化螺栓创建所需的参数
    DObject basicProps = m_paramsHandler.GetDObjectValue(ParamNames.BOLT_BASIC_PROPS);
    DObject holeProps = m_paramsHandler.GetDObjectValue(ParamNames.BOLT_HOLE_PROPS);
    DObject contentProps = m_paramsHandler.GetDObjectValue(ParamNames.BOLT_CONTENT_PROPS);
    DObject extendProps = m_paramsHandler.GetDObjectValue(ParamNames.BOLT_EXTEND_PROPS);
    m_boltParam.CopyFromBasicProps(basicProps);
    m_boltParam.CopyFromHoleProps(holeProps);
    m_boltParam.CopyFromContentProps(contentProps);
    m_boltParam.CopyFromExtendProps(extendProps);
    {
        switch (m_boltParam.SlotIn)
        {
            case BoltParameter.SoltInMode.BEAM:
                m_sectFlags = m_sectFlags | Define.BOLT_SECT_OVERSIZED_HOLE0;
                break;
            case BoltParameter.SoltInMode.PLATE:
                {
                    m_sectFlags = m_sectFlags | Define.BOLT_SECT_OVERSIZED_HOLE1;
                    m_sectFlags = m_sectFlags | Define.BOLT_SECT_OVERSIZED_HOLE2;
                }
                break;
            case BoltParameter.SoltInMode.BOTH:
                {
                    m_sectFlags = m_sectFlags | Define.BOLT_SECT_OVERSIZED_HOLE0;
                    m_sectFlags = m_sectFlags | Define.BOLT_SECT_OVERSIZED_HOLE1;
                    m_sectFlags = m_sectFlags | Define.BOLT_SECT_OVERSIZED_HOLE2;
                }
                break;
            default:
                break;
        }
        if (m_boltParam.PartWasherUp)
        {
            m_sectFlags = m_sectFlags | Define.BOLT_SECT_WASHER_UP;
        }
        if (m_boltParam.PartWasherDown0)
        {
            m_sectFlags = m_sectFlags | Define.BOLT_SECT_WASHER_DOWN0;
        }
        if (m_boltParam.PartWasherDown1)
        {
            m_sectFlags = m_sectFlags | Define.BOLT_SECT_WASHER_DOWN1;
        }
        if (m_boltParam.PartNut0)
        {
            m_sectFlags = m_sectFlags | Define.BOLT_SECT_NUT0;
        }
        if (m_boltParam.PartNut1)
        {
            m_sectFlags = m_sectFlags | Define.BOLT_SECT_NUT1;
        }
    }
    
  2. 创建螺栓,设置起点和终点,螺栓位置由起点控制,终点一般只起决定方向的作用(螺栓的x间距为起点到终点的方向,y间距为另一方向), 创建螺栓共需要五个参数,第一个为key,第二个为主零件,第三个为次零件,第四和第五为控制点(主次零件一定要设置正确,否则影响构建关系,次零件可以有多个)
    bolt_group = m_context.Comp.GetOrCreateBoltGroup("bolt_group" , m_context.MainPart, m_context.SubPart, bolt_st, bolt_st - m_context.Normal_top * 10);
    bolt_group.WorkAxis = new Mat43(-m_context.Normal_front, m_context.Normal_right, m_context.Normal_top, Vec3.ZERO);
    bolt_group.RotationSide = Define.ObjectSide.SIDE_BACK;
    //
    bolt_group.BoltStandard = m_boltParam.BoltStandard;
    bolt_group.BoltSize = m_boltParam.BoltSize;
    bolt_group.HoleTol = m_boltParam.HoleTol;
    bolt_group.ThreadInMtrl = m_boltParam.ThreadInMaterial;
    bolt_group.MadeType = m_boltParam.MadeType0;
    //
    bolt_group.HoleX = m_boltParam.HoleX;
    bolt_group.HoleY = m_boltParam.HoleY;
    bolt_group.HoleType = m_boltParam.HoleType;
    bolt_group.RotateSlot = m_boltParam.RotSlot;
    bolt_group.SectionFlags = m_sectFlags;
    bolt_group.CutLength = 200;
    //
    bolt_group.ExtLength = m_boltParam.ExtLength;
    bolt_group.Shape = Define.BoltGroupShape.BOLT_GROUPSHAPE_ARRAY;
    bolt_group.ArrayStrideX = bolt_xintervals;
    bolt_group.ArrayStrideY = bolt_yintervals;
    bolt_group.Refresh();
    

创建焊缝

创建焊缝有三种创建方式:

  1. 设置参数
    m_weldProps = new List<WeldProperties>();
    for (int i = 0; i < ParamNames.WELD_PROPS_LIST.Length; ++i) 
    {
        DObject weldobj = paramsHandler.GetDObjectValue(ParamNames.WELD_PROPS_LIST[i]);
        weldobj = WeldPropertyPanel.ParseNativeProps(weldobj);
        WeldProperties weldProps = new WeldProperties();
        weldProps.SetProps(weldobj);
        m_weldProps.Add(weldProps);
    }
    
  2. 创建焊缝
    • 自动焊缝有两种方式(特点是简单,但不稳定)
      public Weld CreateWeld(string usage, PartBase main, PartBase sub, Define.SpaceAxis autoWeldPos, int index)
      {
          if (m_weldProps[index].TypeUp == Define.WeldType.WELD_TYPE_NONE && m_weldProps[index].TypeDown == Define.WeldType.WELD_TYPE_NONE)
              return null;
          if (sub == null || main == null)
              return null;
          var weld = m_comp.GetOrCreateAutoWeld(usage, main, sub, autoWeldPos);
          weld.WorkAxis = new Mat43(Normal_top, Normal_right, Normal_front, Vec3.ZERO);
          m_weldProps[index].ApplyToWeld(weld);
          weld.Refresh();
          return weld;
      }
      public Weld CreateWeld(string usage, PartBase main, PartBase sub, Vec3 direction, int index)
      {
          if (m_weldProps[index].TypeUp == Define.WeldType.WELD_TYPE_NONE && m_weldProps[index].TypeDown == Define.WeldType.WELD_TYPE_NONE)
          return null;
          if (sub == null || main==null)
          return null;
          var weld = m_comp.GetOrCreateAutoWeld(usage, main, sub, direction);
          weld.WorkAxis = new Mat43(Normal_top, Normal_right, Normal_front, Vec3.ZERO);
          m_weldProps[index].ApplyToWeld(weld);
          weld.Flush();
          return weld;
      }
      
    • 多边形焊缝有一种方式(用控制点来创建,稳定)
      public void CreateWeld(string usage, PartBase main, PartBase sub, Vec3[] ctrlPoints, int index)
      {
          if (m_weldProps[index].TypeUp == Define.WeldType.WELD_TYPE_NONE && m_weldProps[index].TypeDown == Define.WeldType.WELD_TYPE_NONE)
              return;
          if (sub == null || main==null)
              return;
          var weld = m_comp.GetOrCreatePolyWeld(usage, main, sub, ctrlPoints);
          m_weldProps[index].ApplyToWeld(weld);
      }
      

创建切割面

  • 创建切割面,所需参数第一个为key,第二个为被切割零件,第三个为切割面(切割的部分为法向量的反方向)
    m_context.Comp.GetOrCreateCutPlane("cutter_part", plate, plane);
    

创建对齐面

  • 创建对齐面,所需参数第一个为key,第二个为被对齐零件,第三个为对齐面(对齐的部分为法向量的反方向),注:对齐只能发生在零件的头和尾
    m_context.Comp.GetOrCreateAlignPlane( "Align_part",plate, plane);
    

创建切割体(有两种方式,一个为梁切割,一个为多边形板切割)

创建梁切割体一般分为三步:

  1. 设置切割体创建所需要的两个控制点,即确定切割体的位置(切割体高度也是控制点决定)
  2. 设置切割体的截面,一般有H,I,L等截面通过字符串拼接来设置截面,一般是”截面类型”+”截面厚度”+”截面宽度”
    string Stiff_profile = "PL" + stiff_props.Thickness.ToString() + "*" + ds.ToString();
    
  3. 创建切割体,并设置工作坐标系,名称编号等,创建切割体共需五个参数,第一个为对象用途key,第二个为被切割的物体,第三个为切割体的截面,第四和第五为切割体的两个控制点。
    var cutter_part = m_context.Comp.GetOrCreateBeamCutter("cutter_part",part ,profile, point1, point2);
    

创建多边形板切割体一般分为三步:

  1. 设置切割体创建所需要的四个控制点或者六个包围面,即确定多边形板切割体的位置(多边形板切割体的高和截面的高由控制点或面确定)
  2. 创建多边形板切割体有两种方式,多边形板切割体都是PL类型的截面,故不用设置截面
    • 通过控制点来创建,创建共需五个参数,第一个为对象用途key,第二个为被切割的物体,第三个为多边形切割体的控制点(四个控制点要有顺序),第四个为厚度,第五个为设置多边形板切割体位于四个控制点形成的面的中间还是前面还是后面
      m_context.ConnectComp.GetOrCreatePlateCutter("plate_cutter",m_context.MainPart,ctrlPoints,thickness,Define.ObjectSide.SIDE_MIDDLE);
      
    • 通过面来创建,创建共需要五个参数,第一个为对象用途key,第二个为被切割的物体,第三个为多边形的顶面,第四个为多边形的底面,第五个为多边形的四个侧面(要有顺序)
      m_context.TargetComp.GetOrCreatePlateCutter("plate_cutter",m_context,main_part,top_plane,bottom_plane,side_plane);
      
  3. 一般多边形板都要设置折角,将要设置折角的控制点存入ChamferCtrlPoint中,再设置折角类型和折角大小
    ChamferCtrlPoint[] chamferCtrlPoint = new ChamferCtrlPoint[count];
    chamferCtrlPoint[i].CutType = Define.CornerCutType.CORNER_CUT_ROUND;
    chamferCtrlPoint[i].CutR = x;
    chamferCtrlPoint[i].Refresh();
    

FuncUnit插件开发流程 示例代码:UtilityPluginSample

  • FuncUnit插件开发,创建梁板螺栓等功能创建方法相同,区别在于PluginMain类不相同,和继承类的不同,节点对应ConnectionComponent, 细部对应DetailCompPlugin,utility对应UtilityPlugin,自定义对应ComponentBase类
    public override void OnClick(object sender, EventArgs e, Keys ctrlKeys, LoongCAD.Util.DObject paras) 
    {
        MainForm.Show(this);
    }
    public override void OnDoubleClick(object sender, EventArgs e, Keys ctrlKeys, LoongCAD.Util.DObject paras) 
    {
        //写功能
    }
    

使用FriendlySDK开发组件

使用FriendlySDK开发组件与传统开发过程大致相同,以下列出不同于传统过程的开发细节:

1. 引用相应的名字空间LoongCAD.STC.Friendly.Scene, 并将组件的FriendlyMode属性设置为true

using LoongCAD.STC.Friendly.Scene;

//一个自定义插件例子
public class PluginMain : CustomCompPlugin
{
    public override bool FriendlyMode = true;
}
2. 开发组件时需要使用对应的重载方法和组件类型
组件对应的类与原来的类型不一致,Freindly中的组件类型(都继承于父类BaseComponent):
//Connection类(节点组件)
Connection compConnection = compInst as ConnectComp;
//Detail类(细部组件)
Detail compDetail = compInst as Detail;
//Component类(自定义组件)
Component compCustom = compInst as Component;       

对应生命周期方法的参数变动:
using LoongCAD.STC.Friendly.Scene;
//注意以下方法的参数与传统创建方法的区别
public void OnInstanceRun(BaseComponent compInst);
public override bool OnShowInstancePropsForm(BaseComponent compInst, Form ownerForm);
3. UI界面参数和用户输入参数的传递与传统方式的区别
UI界面参数的传递
using LoongCAD.STC.Friendly.Scene;

public void OnInstanceRun(BaseComponent compInst)
{
    //获取由该组件实例对应的所有UI界面参数
    DObject uiProps = compInst.GetUIProps();

}

用户输入参数传递(自定义组件)
using LoongCAD.STC.Friendly.Scene;

//自定义组件需实现新的捕捉用户输入方法,不再使用原来的实现方式
public override List<InputDefinition> DefineInput()
{
    Picker picker = new Picker();
    //获取用户输入的第一个点
    Point p1 = picker.PickPoint();
    //获取用户输入的第二个点
    Point p2 = picker.PickPoint();

    //传递输入数据
    List<InputDefinition> inputData = new List<InputDefinition>();
    inputData.Add(new InputDefinition(p1));
    inputData.Add(new InputDefinition(p2));
    return inputData;
}

public void OnInstanceRun(BaseComponent compInst)
{
    //获取由该组件实例对应用户输入参数
    Component compCustom = compInst as Component;
    List<InputDefinition> data = compCustom.ComponentInput.InputDefinitions;
    Point p1 = (Point)data[0];
    Point p2 = (Point)data[1];
}

用户输入参数传递(节点组件)
using LoongCAD.STC.Friendly.Scene;

public void OnInstanceRun(BaseComponent compInst)
{
    //获取由该组件实例对应用户输入参数
    Connection compConnection = compInst as ConnectComp;
    Part mainPart = compConnection.PrimaryObject;
    List<Part> subParts = compConnection.SecondaryObjects;
}

用户输入参数传递(细部组件)
using LoongCAD.STC.Friendly.Scene;

public void OnInstanceRun(BaseComponent compInst)
{
    //获取由该组件实例对应用户输入参数
    Detail compDetail = compInst as Detail;
    Part mainPart = compDetail.PrimaryObject;
    Point p = compDetail.ReferencePoint;
}
4. 创建物体时通过创建物体对应类型的单个实例,并调用该实例的insert()方法创建
通过创建对应类型实例和调用实例的insert()方法创建物体,不再需要调用组件的创建方法
//创建梁类型实体
Beam beam = new Beam();
//设置对应参数
beam.StartPoint = new Point(0, 0, 0);
beam.EndPoint = new Point(1000, 0, 0);
beam.Name = "beam";
beam.Profile.ProfileString = "D50";
beam.Material.MaterialString = "Q235B“;
beam.Class = 3;
//在场景中创建
beam.Insert();
5. 改变场景的变换空间
可以改变场景的变换空间,来达到改变物体的工作坐标系的目的
注意:当改变场景的变换空间时,场景内所有物体的位置参数都会随该场景的变换空间变化
//获得该组件实例所在的场景
Scene scene = compInst.Scene;
//改变场景的变换空间
scene.SetCurrentTransformationPlane(new TransformationPlane(Mat43.IDENTITY));