精华内容
下载资源
问答
  • 从0到1,解密Opencascade Topology结构的设计思想

    从0到1,解密Opencascade Topology结构的设计思想

    展开全文
  • 在这一章,你将学到如何在同一个Storm拓扑结构内的不同组件之间传递元组,以及如何向一个运行中的Storm集群发布一个拓扑。 数据流组 设计一个拓扑时,你要做的最重要的事情之一就是定义如何在各组件之间交换...

    在这一章,你将学到如何在同一个Storm拓扑结构内的不同组件之间传递元组,以及如何向一个运行中的Storm集群发布一个拓扑。

    数据流组

    设计一个拓扑时,你要做的最重要的事情之一就是定义如何在各组件之间交换数据(数据流是如何被bolts消费的)。一个数据流组指定了每个bolt会消费哪些数据流,以及如何消费它们。

    NOTE:一个节点能够发布一个以上的数据流,一个数据流组允许我们选择接收哪个。

    数据流组在定义拓扑时设置,就像我们在第二章看到的:

    ···
        builder.setBolt("word-normalizer", new WordNormalizer())
               .shuffleGrouping("word-reader");
    ···

    在前面的代码块里,一个boltTopologyBuilder对象设定, 然后使用随机数据流组指定数据源。数据流组通常将数据源组件的ID作为参数,取决于数据流组的类型不同还有其它可选参数。

    NOTE:每个InputDeclarer可以有一个以上的数据源,而且每个数据源可以分到不同的组。

    随机数据流组(随机分组)

    随机流组是最常用的数据流组。它只有一个参数(数据源组件),并且数据源会向随机选择的bolt发送元组,保证每个消费者收到近似数量的元组。

    随机数据流组用于数学计算这样的原子操作。然而,如果操作不能被随机分配,就像第二章为单词计数的例子,你就要考虑其它分组方式了。

    域数据流组(字段分组)

    域数据流组允许你基于元组的一个或多个域控制如何把元组发送给bolts。它保证拥有相同域组合的值集发送给同一个bolt。回到单词计数器的例子,如果你用word域为数据流分组,word-normalizer bolt将只会把相同单词的元组发送给同一个word-counterbolt实例。

    ···
        builder.setBolt("word-counter", new WordCounter(),2)
               .fieldsGrouping("word-normalizer", new Fields("word"));
    ···

    NOTE: 在域数据流组中的所有域集合必须存在于数据源的域声明中。

    全部数据流组(全部分组)

    全部数据流组,为每个接收数据的实例复制一份元组副本。这种分组方式用于向bolts发送信号。比如,你要刷新缓存,你可以向所有的bolts发送一个刷新缓存信号。在单词计数器的例子里,你可以使用一个全部数据流组,添加清除计数器缓存的功能(见拓扑示例

        public void execute(Tuple input) {
            String str = null;
            try{
                if(input.getSourceStreamId().equals("signals")){
                    str = input.getStringByField("action");
                    if("refreshCache".equals(str))
                        counters.clear();
                }
            }catch (IllegalArgumentException e){
                //什么也不做
            }
            ···
        }

    我们添加了一个if分支,用来检查源数据流。Storm允许我们声明具名数据流(如果你不把元组发送到一个具名数据流,默认发送到名为”default“的数据流)。这是一个识别元组的极好的方式,就像这个例子中,我们想识别signals一样。 在拓扑定义中,你要向word-counter bolt添加第二个数据流,用来接收从signals-spout数据流发送到所有bolt实例的每一个元组。

       builder.setBolt("word-counter", new WordCounter(),2)
               .fieldsGroupint("word-normalizer",new Fields("word"))
               .allGrouping("signals-spout","signals");

    signals-spout的实现请参考git仓库

    自定义数据流组(自定义分组)

    你可以通过实现backtype.storm.grouping.CustormStreamGrouping接口创建自定义数据流组,让你自己决定哪些bolt接收哪些元组。

    让我们修改单词计数器示例,使首字母相同的单词由同一个bolt接收。

    public class ModuleGrouping mplents CustormStreamGrouping, Serializable{
            int numTasks = 0;
            @Override
            public List<Integer> chooseTasks(List<Object> values) {
                List<Integer> boltIds = new ArrayList<Integer>();
                if(values.size()>0){
                    String str = values.get(0).toString();
                    if(str.isEmpty()){
                        boltIds.add(0);
                    }else{
                        boltIds.add(str.charAt(0) % numTasks);
                    }
                }
                return boltIds;
            }
            @Override
            public void prepare(TopologyContext context, Fields outFields, List<Integer> targetTasks) {
                numTasks = targetTasks.size();
            }
        }

    这是一个CustomStreamGrouping的简单实现,在这里我们采用单词首字母字符的整数值与任务数的余数,决定接收元组的bolt

    按下述方式word-normalizer修改即可使用这个自定义数据流组。

     builder.setBolt("word-normalizer", new WordNormalizer())
               .customGrouping("word-reader", new ModuleGrouping());

    直接数据流组(直接分组)

    这是一个特殊的数据流组,数据源可以用它决定哪个组件接收元组。与前面的例子类似,数据源将根据单词首字母决定由哪个bolt接收元组。要使用直接数据流组,在WordNormalizer bolt中,使用emitDirect方法代替emit

    public void execute(Tuple input) {
            ...
            for(String word : words){
                if(!word.isEmpty()){
                    ...
                    collector.emitDirect(getWordCountIndex(word),new Values(word));
                }
            }
            //对元组做出应答
            collector.ack(input);
        }
        public Integer getWordCountIndex(String word) {
            word = word.trim().toUpperCase();
            if(word.isEmpty()){
                return 0;
            }else{
                return word.charAt(0) % numCounterTasks;
            }
        }

    prepare方法中计算任务数

    public void prepare(Map stormConf, TopologyContext context, 
                    OutputCollector collector) {
            this.collector = collector;
            this.numCounterTasks = context.getComponentTasks("word-counter");
        }

    在拓扑定义中指定数据流将被直接分组:

    builder.setBolt("word-counter", new WordCounter(),2)
               .directGrouping("word-normalizer");

    全局数据流组(全局分组)

    全局数据流组把所有数据源创建的元组发送给单一目标实例(即拥有最低ID的任务)。

    不分组(无分组)

    写作本书时(Stom0.7.1版),这个数据流组相当于随机数据流组。也就是说,使用这个数据流组时,并不关心数据流是如何分组的。

    LocalCluster VS StormSubmitter

    到目前为止,你已经用一个叫做LocalCluster的工具在你的本地机器上运行了一个拓扑。Storm的基础工具,使你能够在自己的计算机上方便的运行和调试不同的拓扑。但是你怎么把自己的拓扑提交给运行中的Storm集群呢?Storm有一个有趣的功能,在一个真实的集群上运行自己的拓扑是很容易的事情。要实现这一点,你需要把LocalCluster换成StormSubmitter并实现submitTopology方法, 它负责把拓扑发送给集群。

    下面是修改后的代码:

    //LocalCluster cluster = new LocalCluster();
        //cluster.submitTopology("Count-Word-Topology-With-Refresh-Cache", conf, 
        //builder.createTopology());
        StormSubmitter.submitTopology("Count-Word-Topology-With_Refresh-Cache", conf,
                builder.createTopology());
        //Thread.sleep(1000);
        //cluster.shutdown();

    NOTE: 当你使用StormSubmitter时,你就不能像使用LocalCluster时一样通过代码控制集群了。

    接下来,把源码压缩成一个jar包,运行Storm客户端命令,把拓扑提交给集群。如果你已经使用了Maven, 你只需要在命令行进入源码目录运行:mvn package

    现在你生成了一个jar包,使用storm jar命令提交拓扑(关于如何安装Storm客户端请参考附录A)。命令格式:storm jar allmycode.jar org.me.MyTopology arg1 arg2 arg3

    对于这个例子,在拓扑工程目录下面运行:

    storm jar target/Topologies-0.0.1-SNAPSHOT.jar countword.TopologyMain src/main/resources/words.txt

    通过这些命令,你就把拓扑发布集群上了。

    如果想停止或杀死它,运行:

    storm kill Count-Word-Topology-With-Refresh-Cache

    NOTE:拓扑名称必须保证惟一性。

    NOTE:如何安装Storm客户端,参考附录A

    DRPC拓扑

    有一种特殊的拓扑类型叫做分布式远程过程调用(DRPC),它利用Storm的分布式特性执行远程过程调用(RPC)(见下图)。Storm提供了一些用来实现DRPC的工具。第一个是DRPC服务器,它就像是客户端和Storm拓扑之间的连接器,作为拓扑的spout的数据源。它接收一个待执行的函数和函数参数,然后对于函数操作的每一个数据块,这个服务器都会通过拓扑分配一个请求ID用来识别RPC请求。拓扑执行最后的bolt时,它必须分配RPC请求ID和结果,使DRPC服务器把结果返回正确的客户端。

    NOTE:单实例DRPC服务器能够执行许多函数。每个函数由一个惟一的名称标识。

    Storm提供的第二个工具(已在例子中用过)是LineDRPCTopologyBuilder,一个辅助构建DRPC拓扑的抽象概念。生成的拓扑创建DRPCSpouts——它连接到DRPC服务器并向拓扑的其它部分分发数据——并包装bolts,使结果从最后一个bolt返回。依次执行所有添加到LinearDRPCTopologyBuilder对象的bolts

    作为这种类型的拓扑的一个例子,我们创建了一个执行加法运算的进程。虽然这是一个简单的例子,但是这个概念可以扩展到复杂的分布式计算。

    bolt按下面的方式声明输出:

    public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("id","result"));
        }

    因为这是拓扑中惟一的bolt,它必须发布RPC ID和结果。execute方法负责执行加法运算。

    public void execute(Tuple input) {
            String[] numbers = input.getString(1).split("\\+");
            Integer added = 0;
            if(numbers.length<2){
                throw new InvalidParameterException("Should be at least 2 numbers");
            }
            for(String num : numbers){
                added += Integer.parseInt(num);
            }
            collector.emit(new Values(input.getValue(0),added));
        }

    包含加法bolt的拓扑定义如下:

    public static void main(String[] args) {
            LocalDRPC drpc = new LocalDRPC();
            LinearDRPCTopologyBuilder builder = new LinearDRPCTopologyBuilder("add");
            builder.addBolt(AdderBolt(),2);
            Config conf = new Config();
            conf.setDebug(true);
            LocalCluster cluster = new LocalCluster();
            cluster.submitTopology("drpcder-topology", conf,
                builder.createLocalTopology(drpc));
            String result = drpc.execute("add", "1+-1");
            checkResult(result,0);
            result = drpc.execute("add", "1+1+5+10");
            checkResult(result,17);
            cluster.shutdown();
            drpc.shutdown();
        }

    创建一个LocalDRPC对象在本地运行DRPC服务器。接下来,创建一个拓扑构建器(译者注:LineDRpctopologyBuilder对象),把bolt添加到拓扑。运行DRPC对象(LocalDRPC对象)的execute方法测试拓扑。

    NOTE:使用DRPCClient类连接远程DRPC服务器。DRPC服务器暴露了Thrift API,因此可以跨语言编程;并且不论是在本地还是在远程运行DRPC服务器,它们的API都是相同的。 对于采用Storm配置的DRPC配置参数的Storm集群,调用构建器对象的createRemoteTopology向Storm集群提交一个拓扑,而不是调用createLocalTopology

    转载于:https://my.oschina.net/u/2377453/blog/468144

    展开全文
  • cpu topology

    2017-01-13 11:01:28
    struct cpu_topology {  int thread_id;  int core_id;  int cluster_id;  cpumask_t thread_sibling;  cpumask_t core_sibling; }; 可以看到cpu 拓扑结构相关的就是cluster/core/thread.
    cpu的拓扑结构的定义如下:
    struct cpu_topology {
        int thread_id;
        int core_id;
        int cluster_id;
        cpumask_t thread_sibling;
        cpumask_t core_sibling;
    };
    可以看到cpu 拓扑结构相关的就是cluster/core/thread. 平时我们用lscpu看到就是这三个.
    lscpu
    Architecture:          aarch64
    Byte Order:            Little Endian
    CPU(s):                64
    On-line CPU(s) list:   0-63
    Thread(s) per core:    1
    Core(s) per socket:    4
    Socket(s):             16
    NUMA node(s):          4
    NUMA node0 CPU(s):     0-15
    NUMA node1 CPU(s):     16-31
    NUMA node2 CPU(s):     32-47
    NUMA node3 CPU(s):     48-63
    kernel_init_freeable->smp_prepare_cpus->init_cpu_topology 来从dts表中parse cluster/core/thread的值填到cpu_topology 结构体中
    void __init init_cpu_topology(void)
    {
        reset_cpu_topology();

        /*
         * Discard anything that was parsed if we hit an error so we
         * don't use partial information.
         */
        if (of_have_populated_dt() && parse_dt_topology())
            reset_cpu_topology();
    }
    init_cpu_topology 首先调用将cpu_topology 结构体清零
    static void __init reset_cpu_topology(void)
    {
        unsigned int cpu;

        for_each_possible_cpu(cpu) {
            struct cpu_topology *cpu_topo = &cpu_topology[cpu];

            cpu_topo->thread_id = -1;
            cpu_topo->core_id = 0;
            cpu_topo->cluster_id = -1;

            cpumask_clear(&cpu_topo->core_sibling);
            cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
            cpumask_clear(&cpu_topo->thread_sibling);
            cpumask_set_cpu(cpu, &cpu_topo->thread_sibling);
        }
    }
    然后调用of_have_populated_dt()判断当前是否有dts.判断的方法如下:
    static inline bool of_have_populated_dt(void)
    {
        return of_root != NULL;
    }
    从这个判断也可以看到当前4.9的kernel中的cpu topology 不支持ACPI传递.
    of_have_populated_dt()判断通过后就通过parse_dt_topology 来parse cluster/core/thread的值填到cpu_topology 结构体中。如果失败则调用reset_cpu_topology来清零
    static int __init parse_dt_topology(void)
    {
        struct device_node *cn, *map;
        int ret = 0;
        int cpu;

        cn = of_find_node_by_path("/cpus");
        if (!cn) {
            pr_err("No CPU information found in DT\n");
            return 0;
        }

        /*
         * When topology is provided cpu-map is essentially a root
         * cluster with restricted subnodes.
         */
        map = of_get_child_by_name(cn, "cpu-map");
        if (!map)
            goto out;

        ret = parse_cluster(map, 0);
        if (ret != 0)
            goto out_map;

        /*
         * Check that all cores are in the topology; the SMP code will
         * only mark cores described in the DT as possible.
         */
        for_each_possible_cpu(cpu)
            if (cpu_topology[cpu].cluster_id == -1)
                ret = -EINVAL;

    out_map:
        of_node_put(map);
    out:
        of_node_put(cn);
        return ret;
    }
    这个函数首先判断是否有/cpu这个节点,然后从cpu节点中找到cpu-map 这个子节点
    然后调用parse_cluster来parse cluster
    parse_cluster 先parse cluser再parse core
    static int __init parse_core(struct device_node *core, int cluster_id,
                     int core_id)
    {
        char name[10];
        bool leaf = true;
        int i = 0;
        int cpu;
        struct device_node *t;

        do {
            snprintf(name, sizeof(name), "thread%d", i);
            t = of_get_child_by_name(core, name);
            if (t) {
                leaf = false;
                cpu = get_cpu_for_node(t);
                if (cpu >= 0) {
                    cpu_topology[cpu].cluster_id = cluster_id;
                    cpu_topology[cpu].core_id = core_id;
                    cpu_topology[cpu].thread_id = i;
                } else {
                    pr_err("%s: Can't get CPU for thread\n",
                           t->full_name);
                    of_node_put(t);
                    return -EINVAL;
                }
                of_node_put(t);
            }
            i++;
        } while (t);

        cpu = get_cpu_for_node(core);
        if (cpu >= 0) {
            if (!leaf) {
                pr_err("%s: Core has both threads and CPU\n",
                       core->full_name);
                return -EINVAL;
            }

            cpu_topology[cpu].cluster_id = cluster_id;
            cpu_topology[cpu].core_id = core_id;
        } else if (leaf) {
            pr_err("%s: Can't get CPU for leaf core\n", core->full_name);
            return -EINVAL;
        }

        return 0;
    }
    最终在parse_core 函数中将dts中的到的信息填到cpu_topology 这个结构体中。





    展开全文
  • Topology and Geometry in OpenCascade-Topology eryar@163.com 摘要Abstract:本文简要介绍了几何造型中的边界表示法(BRep),并结合程序说明OpenCascade中的边界表示的具体实现,即拓朴与几何的联系。对具有...

    Topology and Geometry in OpenCascade-Topology

    eryar@163.com

    摘要Abstract:本文简要介绍了几何造型中的边界表示法(BRep),并结合程序说明OpenCascade中的边界表示的具体实现,即拓朴与几何的联系。对具有几何信息的拓朴结构顶点(vertex)、边(edge)、面(face)进行了详细说明。本文通过ACIS与OpenCascade进行对比来对拓朴(Topology)的概念进行说明。并通过示例程序,说明如何在OpenCascade中取得与一个拓朴对象相连的其他拓朴对象,包括父对象和子对象。 

    关键字Key Words:OpenCascade、ACIS、BRep、Topology、Geometry 

    一、引言 Introduction

    边界表示(Boundary Representation)也称为BRep表示,它是几何造型中最成熟、无二义的表示法。实体的边界通常是由面的并集来表示,而每个面又由它所在的曲面的定义加上其边界来表示,面的边界是边的并集,而边又是由点来表示的。 

    边界表示的一个重要特征是描述形体的信息包括几何信息(Geometry)和拓朴信息(Topology)两个方面。拓朴信息描述形体上的顶点、边、面的连接关系,它形成物体边界表示的“骨架”。形体的几何信息犹如附着在“骨架”上的肌肉。例如,形体的某个面位于某一个曲面上,定义这一曲面方程的数据就是几何信息。此外,边的形状、顶点在三维空间中的位置(点的坐标)等都是几何信息,一般来说,几何信息描述形体的大小、尺寸、位置和形状等。 

    在边界表示法中,边界表示就按照体-面-环-边-点的层次,详细记录构成形体的所有几何元素的几何信息及其相互连接的拓朴关系。这样,在进行各种运算和操作中,就可以直接取得这些信息。 

    拓朴是指一个模型中的不同实体之间的关系,它描述了几何实体之间的连接方式。拓朴定义了一个空间位置不固定的浮动模型。当拓朴实体与几何信息关联在一起时,它的空间位置才确定。 

    拓朴可以是有边界的、没边界的和半封闭的,它允许实体是完全实体,也可以是不完全实体。例如,实体可以没有面,面可以没有边,实体也可以从内部将它分割成壳的内部面。这种实体在物理世界中是不存在的,但在几何造型内核中可以表现出来。 

    二、ACIS中的拓朴结构 Topology of ACIS

    ACIS模型的边界表示(B-Rep)是将模型的拓朴结构按层次分解成下述对象: 

    1. 体(Body):是实体对象的最高层次,是块(lump)的集合。体可以是线、面、或实心体; 

    2. 块(Lump):空间一维、二维或三维点连接而成的集合,与其他块(lump)不关联,其边界由壳(shell)组成; 

    3. 壳(Shell):互联的线或面的集合,它可以界定实体的外部或内部区域; 

    4. 子壳(Subshell):壳的进一步分解,用于处理内部处理算法的效率; 

    5. 面(Face):被一个或多个边(edge)组成的环(loop)界定的曲面中的连通域。面可以是“双向”的,这时它的厚度趋于无穷小。面也可以是“单向”的,这时面的法线指向面的外部,另一边侧是面的内部; 

    6. 环(Loop):面(face)的边界中互相连接的部分,它由一系列的有向边(coedge)组成。通常环是封闭的,没有实际的开始和结束点,但是ACIS中的环可以是开环; 

    7. 线(Wire):没有附着在面上的,连接在一起的有向边(coedge); 

    8. 有向边(Coedge):表示面(face)或线(wire)中对某个边的引用; 

    9. 边(Edge):与曲线关联的拓朴,由顶点(vertex)界定。 

    10. 顶点(Vertex):点是几何造型中的最基本元素。用计算机存储、管理、输出形体的实质就是对点集及其连接关系的处理。 

    wps_clip_image-6000

    Figure 2.1 Topology of ACIS 

    上图说明了概念上的拓朴对象之间的关系,这些对象组成了ACIS边界表示方法的基础。它们在ACIS中分别用类BODY、LUMP、SHELL、SUBSHELL、FACE、LOOP、WIRE、COEDGE、EDGE和VERTEX实现,这些类派生于类ENTITY。 

    ACIS通过在它的数据结构中整合了线框、曲面和实体这三种表示方法,将这三种不同的几何体联系在一起。线框实体可以和实体(solid)与面实体共享,它们可以是共享边、有向边与顶点。由于这种共存的实现,使ACIS具有了表示混合维度模型与各种各样不封闭模型的能力,如一个平面可以只在3个方向上有边界边,另外一方向没有边界。 

    wps_clip_image-11877

    Figure 2.2 Class Diagram of ACIS Topology 

    ACIS的对象都有包围盒(Bound),这在求交运算中很有用,可以提高效率。如果两个对象的包围盒相交,那么这两个对象则可能相交,然后再执行更精确的求交运算。如果两个对象的包围盒不相交,则这两个对象一定不相交,这样进一步的精确求交运算就不需要了。 

    既然拓朴表示了各对象之间的连接关系,那么给定一个对象时,可以容易得到其相连接其它对象。图3说明了ACIS中组成实体、面、线和混合体的所有实体类,这些类及其方法提供了一个边界表示造型器所必需的数据和方法。层次关系中向上和向下的指示说明这些类之间允许数据的快速切换,利用这种功能就可以确定两个实体是否共享边或顶点。从图中可以看出拓朴类都有指向对应的几何体类的指针。 

    wps_clip_image-8073

    Figure 2.3 Topology structure of ACIS 

    从上图可以看出,任意给定一个对象,可以快速获得与其相连的其它对象,不管是向下还是向上。如给定一个FACE对象,可以通过loop()向下获得LOOP对象;可以通过shell()向上获得SHELL对象。 

    除了顶点以外,其他拓朴对象都有bound(),可以取得其包围盒。 

    下面是统计一个模型中所有面的数量的程序,该程序就是利用拓朴类的公共成员函数来完成面的统计功能。通过这个程序来说明函数的使用方法。 

    wps_clip_image-11521

      

    三、OpenCascade中的拓朴结构 Topology of OpenCascade

    3.1 OpenCascade拓朴简介 Introduction of OpenCascade Topology

    OpenCascade中的拓朴(topology)是根据STEP标准ISO-10303-42设计的。也许读一下这个标准中的有关概念还是很有帮助的。STEP ISO-10303-42的相关资源: 

    http://www.steptools.com/support/stdev_docs/express/step_irs/index.html

    wps_clip_image-6429

    Figure 3.1 Topology data structure in OpenCascade 

    wps_clip_image-12719

    TopoDS_Shape由值控制,包含三个成员变量:myLocation、myOrient、myTShape。 

    wps_clip_image-16890

    Figure 3.2 TopoDS_Shape member fields 

    其中TopoDS_TShape中包含与此对象相连接的子对象。 

    下图所示为由一条边连接的两个面组成的壳(shell): 

    wps_clip_image-28930

    Figure 3.3 Structure of a shell formed from two faces 

    上图所示的形状表示为TS, 面TF1和TF2,有七条边TE1~TE7和六个顶点TV1~TV6。 

    环TW1引用边TE1~TE4;环TW2引用TE4~TE7 。边引用的顶点如下:TE1(TV1,TV4),TE2(TV1,TV2),TE3(TV2,TV3),TE4(TV3,TV4),TE5(TV4,TV5),TE6(TV5,TV6),TE7(TV3,TV6)。 

    wps_clip_image-14945

    Figure 3.4 Data structure of the shell formed from two faces connected at an edge 

    注:OpenCascade中的这个数据结构中不包含“反向引用(back references)”,即所有的引用只从复杂形状到简单形状。(Note that this data structure does not contain any “back references”. All references go from more comples underlying shapes to less complex ones.)有点有向图的意思。

    这个根据OpenCascade的拓朴结构的类图可知,访问形状的子对象是很容易的。为了获得一个对象的拓朴,不管是向上还是向下,OpenCascade提供了专门类和函数来实现。当向下访问拓朴对象时,OpenCascacde提供了两种方法来遍历子对象。向上遍历时,OpenCascade提供了一个静态函数TopExp::MapShapesAndAncestors()来实现。以下分别对其进行说明。 

    3.2 遍历子对象 Iteration over Children

    遍历子对象是向下来访问拓朴关系。OpenCascade中遍历一个形状的子对象的两个方法分别为: 

    l 直接使用类TopoDS_Iterator来遍历: 

    Direct children can be retrieved using TopoDS_Iterator,如下函数可以访问当前对象所有的子对象,不管子对象的类型。通过递归的方式来实现。

    void TraverseShape(const TopoDS_Shape& theShape)
    {
        TopoDS_Iterator anIt(theShape);
        for ( ; anIt.More(); anIt.Next() )
        {
            const TopoDS_Shape& aChild = anIt.Value();
            TraverseShape(aChild);
        }
    }

    TopoDS_Iterator有两个标志位,用于控制在查询子对象时设定是否考虑父对象的位置和朝向(location and orientation)。若位置(location)标志设置为开,那么所有子对象返回的值就像它们是独立的对象一样,而且位置是在具有全局坐标系的三维空间中的位置。(例如用户将看到单独取出来的边edge与其父对象环wire中显示的位置是一样的。)若朝向(orientation)标设置为开,则返回的子对象的朝向将会变成父对象的朝向与子对象朝向的乘积(例如,子对象和父对象两者都是反向reversed或是向前forward,则结果仍然向前。向前与反向的任意组合结果都将为反向)。 

    若标志位为关,则子对象就只返回其自身保存的位置和朝向。默认情况下,两个标志位都设置为开。 

    l 使用类TopExp_Explorer来遍历指定类型的子对象: 

    若只想访问形状指定类型的子对象,可以使用类TopExp_Explorer来实现。如下程序所示为访问对象的边的功能。

    TopExp_Explorer anExp(theShape, TopAbs_EDGE);
    for (; anExp.More(); anExp.Next() )
    {
        const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
        // do something with anEdge
    }

    类TopExp_Explorer还有一个附加参数,可以用来指定要跳过的父对象类型。这个参数在下面的情况下很有用。例如只想取得“悬空”边(floating edge, 即不属于面的边),就可用下面代码来实现:

    TopExp_Explorer aFloatingEdgeExp(theShape, TopAbs_EDGE, TopAbs_FACE);

     

    3.3 反向引用 Back references

    在使用OpenCascade时,你可能也注意到了,或者根据类图分析到拓朴对象包含其子对象,而不是相反的方式。这是可以理解的,同一个对象或者子对象可以属于不同的对象。例如任意共享边可以属于至少两个面。然而有时也需要从子对象追踪到与其相连的父对象。在OpenCascade中提供了静态函数TopExp::MapShapesAndAncestors()来实现这个功能。

    TopTools_IndexedDataMapOfShapeListOfShape anEFsMap;
    TopExp::MapShapesAndAncestors (myShape, TopAbs_EDGE, TopAbs_FACE, anEFsMap);

    上面的代码生成了myShape中面和边之间的映射。若myShape是长方体,每一条边会映射到两个面上。若遍历同样的长方体,并在每一个面中尽力找到边的父对象,那么明显的该映射中一条边只有一个面,也就是当前正在搜索的面。 

      

    四、示例程序 Example Code

    1. 统计一个长方体面的数量

    /*
    *    Copyright (c) 2013 eryar All Rights Reserved.
    *
    *        File    : Main.cpp
    *        Author  : eryar@163.com
    *        Date    : 2013-09-21 11:58
    *        Version : 1.0v
    *
    *    Description : Count faces of a box. 
    *                  
    */
    
    // OpenCascade library.
    #define WNT
    #include <BRepPrimAPI_MakeBox.hxx>
    #include <TopExp_Explorer.hxx>
    
    #pragma comment(lib, "TKernel.lib")
    #pragma comment(lib, "TKMath.lib")
    #pragma comment(lib, "TKBRep.lib")
    #pragma comment(lib, "TKTopAlgo.lib")
    #pragma comment(lib, "TKPrim.lib")
    
    int main(void)
    {
        Standard_Integer nFaceCount = 0;
        TopoDS_Shape aBox = BRepPrimAPI_MakeBox(100, 150, 200);
    
        for (TopExp_Explorer faceExp(aBox, TopAbs_FACE); faceExp.More(); faceExp.Next())
        {
            nFaceCount++;
        }
    
        std::cout << "The box has " << nFaceCount << " faces." << std::endl;
    
        return 0;
    }

    程序输出结果为:

    1 The box has 6 faces. 

      

    2. 反向访问

    /*
    *    Copyright (c) 2013 eryar All Rights Reserved.
    *
    *        File    : Main.cpp
    *        Author  : eryar@163.com
    *        Date    : 2013-09-21 11:58
    *        Version : 1.0v
    *
    *    Description : Demonstrate how to access parent and child topology data
    *       for a given topology shape.
    *                  
    */
    
    // OpenCascade library.
    #define WNT
    #include <BRepPrimAPI_MakeBox.hxx>
    #include <TopExp_Explorer.hxx>
    #include <TopoDS.hxx>
    #include <TopExp.hxx>
    #include <TopTools_ListOfShape.hxx>
    #include <TopTools_ListIteratorOfListOfShape.hxx>
    #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
    
    #pragma comment(lib, "TKernel.lib")
    #pragma comment(lib, "TKMath.lib")
    #pragma comment(lib, "TKBRep.lib")
    #pragma comment(lib, "TKTopAlgo.lib")
    #pragma comment(lib, "TKPrim.lib")
    
    void dumpVertex(const TopoDS_Vertex& vertex)
    {
        gp_Pnt pnt = BRep_Tool::Pnt(vertex);
    
        std::cout << "(" << pnt.X() << ", " << pnt.Y() << ", " << pnt.Z() << ")" << std::endl;
    }
    
    int main(void)
    {
        TopoDS_Shape aBox = BRepPrimAPI_MakeBox(100, 150, 200);
    
        TopTools_IndexedDataMapOfShapeListOfShape shapeMap;
        TopTools_ListOfShape edges;
        TopTools_ListIteratorOfListOfShape edgeItr;
    
        // Use TopExp_Explorer to access subshapes.
        TopExp_Explorer vertexExp(aBox, TopAbs_VERTEX);
    
        const TopoDS_Vertex& aVertex = TopoDS::Vertex(vertexExp.Current());
    
        // Use TopExp::MapShapesAndAncestors() to access parent shapes.
        TopExp::MapShapesAndAncestors(aBox, TopAbs_VERTEX, TopAbs_EDGE, shapeMap);
        
        edges = shapeMap.FindFromKey(aVertex);
    
        dumpVertex(aVertex);
    
        for (edgeItr.Initialize(edges); edgeItr.More(); edgeItr.Next() )
        {
            const TopoDS_Edge& anEdge = TopoDS::Edge(edgeItr.Value());
    
            std::cout << "Vertex belong to the Edge: " << std::endl;
            dumpVertex(TopExp::FirstVertex(anEdge));
            dumpVertex(TopExp::LastVertex(anEdge));
            std::cout << "---------------------------" << std::endl;
        }
    
        return 0;
    }

    程序输出结果:

    (0, 0, 200)
    Vertex belong to the Edge:
    (0, 0, 0)
    (0, 0, 200)
    ---------------------------
    Vertex belong to the Edge:
    (0, 0, 200)
    (0, 150, 200)
    ---------------------------
    Vertex belong to the Edge:
    (0, 0, 200)
    (100, 0, 200)
    ---------------------------
    Vertex belong to the Edge:
    (0, 0, 0)
    (0, 0, 200)
    ---------------------------
    Vertex belong to the Edge:
    (0, 0, 200)
    (0, 150, 200)
    ---------------------------
    Vertex belong to the Edge:
    (0, 0, 200)
    (100, 0, 200)
    ---------------------------

      

    五、结论 Conclusion

    OpenCascade中的拓朴关系不像ACIS中那样直接,但是也提供了向下访问子形状、向上访问父形状的类和函数,使用起来要涉及到好几个类,不是很方便。 

    当向上访问与顶点相连接的边时,有重复数据。 

      

    六、参考资料 References

    1. Roman Lygin, OpenCascade notes, opencascade.blogspot.com 

    2. 詹海生等, 基于ACIS的几何造型技术与系统开发, 清华大学出版社, 2002 

    3. 孙家广等. 计算机图形学. 清华大学出版社 

    4. OpenCascade source code. 

     

    转载于:https://www.cnblogs.com/opencascade/p/3608508.html

    展开全文
  • SONA Topology

    2018-04-28 20:17:00
    N多年以前就有有人设计传了一种类似“房子”状结构的拓扑图,在Cisco的文档中可以查到这种叫SONA。这是个非常神奇的设计,适合用于中小型网络,之所以这么讲,是因为在这个结构下,但凡任何一台接入层或者汇聚层...
  • 微微网拓扑结构(piconet topology) 1、BR/EDR 拓扑结构(BR/EDR Topology) 任何时候使用BR/EDR控制器创建链接时,它都在piconet上下文中。微微网由两个或多个设备组成,它们占用相同的BR/EDR物理通道。 连接...
  • 在总线型Daisy Chain拓扑结构中,每一工作站会利用一根电缆与其上游或下游的设备直接连接,Phonenet及Etherwave是采用Daisy Chain的拓扑结构。 Daisy Chain拓扑结构的好处是容易将所有设备连接在一起,相对于...
  • The word of topology is borrowed from geometry. It is used to describe the shape of the network and how its layout or how network connected in physically. Topology will show how network server, ...
  • Linux CPU Topology

    千次阅读 2016-03-30 15:28:26
    原文:http://www.wowotech.net/pm_subsystem/cpu_topology.html 1. 前言 在“Linux CPU core的电源管理(1)_概述”中,我们多次...它们和CPU的进化过程息息相关,最终会体现在CPU topology(拓扑结构)上。因此本
  • 玩转CPU Topology

    2016-03-11 10:35:52
    如果你也是对/proc/cpuinfo文件里面的内容不甚了解,请跟我一起来学习下CPU的拓扑结构 (CPU Topology)。我们先从一些简单的概念开始。 NUNA与SMP NUMA(Non-Uniform Memory Access,非一致性内存访问)和SMP(Symmetric...
  • Open CASCADE Topology

    千次阅读 2009-03-12 16:37:00
    而Open CASCADE Geometry通过坐标或参数值描述物体,Topology在参数空间使用参数空间的位置或约束来描述数据的结构。 quote:参数空间:对一条平面曲线,显式表示的一般形式是:y=f(x).隐式表示:f(x,y)=0。用非参数...
  • JStorm之Topology调度

    2018-02-10 15:06:00
    topology在服务端提交过程中,会经过一系列的验证和初始化:TP结构校验、创建本地文件夹并拷贝序列化文件jar包、生成znode用于存放TP和task等信息,最后一步才进行任务分配。例如以下图: 提交主函数位于Service...
  • Mikrotik-Topology-源码

    2021-03-26 01:19:29
    仅此拓扑结构,在建筑物内的每个楼层中还包含4个路由器热点,这些路由器由大约100个用户使用。 这种拓扑结构在由混凝土墙制成的建筑物内部很有用。 此项目已获得GNU Public License V3的版权许可。 未经作者许可,...
  • Storm集群和Hadoop集群表面上看很类似。...Topology的定义是一个Thrift结构,并且Nimbus就是一个Thrift服务, 你可以提交由任何语言创建的topology。 作者:毅山,宋智来源:量子恒道官方博客|2013-08-29 14:28
  • JTS Topology Suite

    千次阅读 2013-02-21 23:34:09
    【主页】http://tsusiatsoftware.net/jts/main.html 【主页】http://sourceforge.net/projects/jts-topo-suite/ 【API】... 主要类及其继承结构: Coordinate类: 构造——
  • 多位移约束下的多工况结构拓扑优化,多位移约束下的多工况结构拓扑优化
  • Trident Topology开发Demo

    2018-06-09 21:12:00
    1.项目结构 ·  2.启动的服务  无 3.驱动程序 1 package com.jun.trident; 2 3 import backtype.storm.Config; 4 import backtype.storm.LocalCluster; 5 import backtype.storm....
  • PCB Design Rules﹣Routing Topology(PCB设计规则﹣布线拓扑)是Altium Designer18中“PCB Rules and Constraints Editor”对话框第二项功能Routing布线的第二个页面,如下图所示。 Summary摘要 该规则指定了...
  • Topology Shapes of OpenCascade BRep eryar@163.com 摘要Abstract:通过对OpenCascade中的BRep数据的读写,理解边界表示法的概念及实现。理解了拓朴形状的数据结构,就对ModelingData模块有了清晰认识,方便...
  • Storm系统的数据处理应用单元,是被打包的被称为Topology的作业。 它是由多个数据处理阶段组合而成的,而每个处理阶段在构造...而Topology就是这两类组件通过数据流连接的一种计算逻辑结构。(也就是说,上一个组建...
  • 功能:提交一个新的Topology,并为Topology创建storm-id(topology-id),校验其结构,设置必要的元数据,最后为Topology分配任务. 实现源码: 1 (^voidsubmitTopology 2 [this...
  • 高通平台的音频Topology

    千次阅读 2013-09-04 18:54:39
    废话少说,进入主题:什么是Topology? 翻译成中午的意思是拓扑,理科生的我们对这个词并不陌生,大概就是指一些结构,比如我们学习网络的时候经常看到网络拓扑图。 在音频系统中,声音是经过很多模块处理的,可以...
  • 它们和CPU的进化过程息息相关,最终会体现在CPU topology(拓扑结构)上。因此本文将以CPU topology为主线,介绍CPU有关(主要以ARM CPU为例)的知识。 另外,CPU topology除了描述CPU的组成之外,其主要功能,是向...
  • 在driver/base下面还有一个topology.c 这个文件只要是生成sys文件接口,方便用户同下面的接口查询cpu的拓扑结构. [root@CentOS sda1]# cd /sys/devices/system/cpu/cpu0/ driver/ firmware_node/ hotplug/ node0...
  • Flink1.11 任务报错:No operators defined in streaming topology 解决:可以看看你的代码结构是不是以下这种 val bsEnv = StreamExecutionEnvironment.getExecutionEnvironment val bsSettings = Environment...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 495
精华内容 198
关键字:

topology结构