2014-11-23

Grouping Geometric Features Not Sharing Attribute

属性を共有しないジオメトリのグループ化

In this thread, I suggested a solution which includes a Python script to group consecutively adjoining triangular polygons. The point of the script is to use "set" skilfully.
このスレッドでは、連続して隣接する三角形ポリゴンをグループ化するために、Pythonスクリプトを含む解決策を提案しました。スクリプトのポイントは"set"(集合)をうまく使うことです。
FME Community Answers > SpatialRelator with 3D data

The logic could be applied to some other similar scenarios.
For example, consider a case where you need to group discrete areas based on their closeness, like this image. i.e. make a group for areas which are close within a certain distance each other.
Assume that the features don't have any attributes which can be used to group them.
そのロジックは他の似たようなシナリオにも応用できそうです。
例えば次の画像のように、離散的な領域を近さに基づいてグループ化する必要がある場合、つまり、相互に一定の距離以内にある領域をひとつのグループにするような場合を考えます。
フィーチャーは、それらをグループ化するのに使える属性は持っていないものとします。

Input: Individual area features
入力: 個々の領域フィーチャー







Required Result: Grouped based on their closeness
求められる結果: 近さに基づいてグループ化








This is a possible way to group them (add group ID attribute).
1) Use a Counter to add area ID (sequential number, e.g. "_area_id") to the input features.
2) Add a NeighborFinder; send the all features to the Candidate port, set the "Maximum Distance" and the "Close Candidate List Name" parameter (e.g. "_close").
3) Send features output from the Matched port and the UnmatchedCandidate port to a PythonCaller with this script; expose the group ID attribute ("_group_id" in this script example).
以下はそれらをグループ化する(グループID属性を与える)ための可能な方法です。
1) Counterを使い、領域ID(連番。例えば"_area_id")を入力フィーチャーに与える。
2) NeighborFinderを追加し、全てのフィーチャーをCandidateポートに送り、"Maximum Distance"パラメーターと"Close Candidate List Name"パラメーター(例えば"_close")を設定する。
3) MatchedポートとUnmuchedCandidateポートから出力されるフィーチャーを次のスクリプトを設定したPythonCallerに送り、グループID属性(このスクリプトの例では"_group_id")を公開する。
-----
# Python Script Example
import fmeobjects

class GroupIdSetter(object):
    def __init__(self):
        self.features = {} # Key: Area ID => Value: Feature Object
        self.groups = {} # Key: Area ID => Value: Set of Area IDs in Group

    def input(self, feature):
        areaId = int(feature.getAttribute('_area_id'))
        self.features[areaId] = feature
        grp = self.groups.setdefault(areaId, set([areaId]))
        neighbors = feature.getAttribute('_close{}._area_id')
        if neighbors:
            for id in [int(s) for s in neighbors]:
                grp |= self.groups.setdefault(id, set([id]))
        for id in grp:
            self.groups[id] = grp
     
    def close(self):
        groupId, finished = 0, set([])
        for id, grp in self.groups.items():
            if id not in finished:
                for areaId in grp:
                    feature = self.features[areaId]
                    feature.setAttribute('_group_id', groupId)
                    self.pyoutput(feature)
                groupId += 1
                finished |= grp
=====
2014-11-26: The "close" method might be a little more efficient if written like this.
"close"メソッドは次のようにも書いた方がもう少し効率的かも知れない。
-----
    def close(self):
        groupId = 0
        for grp in self.groups.values():
            if grp:
                while grp:
                    feature = self.features[grp.pop()]
                    feature.setAttribute('_group_id', groupId)
                    self.pyoutput(feature)
                groupId += 1
=====

But there is also another approach which does not use any script in this example case..
もっとも、この例の場合にはスクリプトを使わないアプローチもあるのですが。









... yup, found out the solution at last, in which I've used the buffering trick.
... お、やっと見つけました。バッファリングを使ったソリューション。
FME Community Answers > Aggregating polygons near to one another

=====
2014-11-27: I published a custom transformer called "ListCombiner" in the FME Store, which can be applied to the scenario example above. This screenshot illustrates a usage example.
上のシナリオ例に適用できる"ListCombiner"というカスタムトランスフォーマーをFME Storeで公開しました。このスクリーンショットは使用例を示しています。

No comments:

Post a Comment