Ejemplo n.º 1
0
void
NWWriter_SUMO::writeRoundabout(OutputDevice& into, const std::vector<std::string>& edgeIDs,
                               const NBEdgeCont& ec) {
    std::vector<std::string> validEdgeIDs;
    std::vector<std::string> invalidEdgeIDs;
    std::vector<std::string> nodeIDs;
    for (std::vector<std::string>::const_iterator i = edgeIDs.begin(); i != edgeIDs.end(); ++i) {
        const NBEdge* edge = ec.retrieve(*i);
        if (edge != 0) {
            nodeIDs.push_back(edge->getToNode()->getID());
            validEdgeIDs.push_back(edge->getID());
        } else {
            invalidEdgeIDs.push_back(*i);
        }
    }
    std::sort(nodeIDs.begin(), nodeIDs.end());
    if (validEdgeIDs.size() > 0) {
        into.openTag(SUMO_TAG_ROUNDABOUT);
        into.writeAttr(SUMO_ATTR_NODES, joinToString(nodeIDs, " "));
        into.writeAttr(SUMO_ATTR_EDGES, joinToString(validEdgeIDs, " "));
        into.closeTag();
        if (invalidEdgeIDs.size() > 0) {
            WRITE_WARNING("Writing incomplete roundabout. Edges: '"
                          + joinToString(invalidEdgeIDs, " ") + "' no longer exist'");
        }
    }
}
Ejemplo n.º 2
0
std::string
getVehicleClassNames(SVCPermissions permissions) {
    if (permissions == SVCAll) {
        return "all";
    }
    return joinToString(getVehicleClassNamesList(permissions), ' ');
}
void
NWWriter_SUMO::writeRoundabout(OutputDevice& into, const EdgeVector& r) {
    std::vector<std::string> edgeIDs;
    std::vector<std::string> nodeIDs;
    for (EdgeVector::const_iterator j = r.begin(); j != r.end(); ++j) {
        edgeIDs.push_back((*j)->getID());
        nodeIDs.push_back((*j)->getToNode()->getID());
    }
    // make output deterministic
    std::sort(edgeIDs.begin(), edgeIDs.end());
    std::sort(nodeIDs.begin(), nodeIDs.end());
    into.openTag(SUMO_TAG_ROUNDABOUT);
    into.writeAttr(SUMO_ATTR_NODES, joinToString(nodeIDs, " "));
    into.writeAttr(SUMO_ATTR_EDGES, joinToString(edgeIDs, " "));
    into.closeTag();
}
Ejemplo n.º 4
0
std::string
MSContainer::MSContainerStage_Driving::getStageSummary() const {
    const std::string dest = (getDestinationStop() == 0 ? 
        " edge '" + getDestination()->getID() + "'" : 
        " stop '" + getDestinationStop()->getID() + "'");
    return isWaiting4Vehicle() ? 
        "waiting for " + joinToString(myLines, ",") + " then transported to " + dest: 
        "transported to " + dest;
}
Ejemplo n.º 5
0
GNEInspectorFrame::AttrEditor::AttrEditor(AttrInput* attrInputParent, FXTextField* textFieldAttr) :
    FXDialogBox(attrInputParent->getApp(), ("Editing attribute '" + toString(attrInputParent->getAttr()) + "'").c_str(), DECOR_CLOSE | DECOR_TITLE),
    myAttrInputParent(attrInputParent),
    myTextFieldAttr(textFieldAttr) {
    // Create matrix
    myCheckBoxMatrix = new FXMatrix(this, 2, GUIDesignMatrixAttributes);

    // Obtain vector with the choices
    const std::vector<std::string>& choices = GNEAttributeCarrier::discreteChoices(myAttrInputParent->getTag(), myAttrInputParent->getAttr());

    // Get old value
    const std::string oldValue = myTextFieldAttr->getText().text();

    // Resize myVectorOfCheckBox
    myVectorOfCheckBox.resize(choices.size(), NULL);

    // Iterate over choices
    for (int i = 0; i < (int)choices.size(); i++) {
        // Create checkBox
        myVectorOfCheckBox.at(i) = new FXCheckButton(myCheckBoxMatrix, choices.at(i).c_str(),NULL, 0, GUIDesignCheckButtonAttribute);
        // Set initial value
        if (oldValue.find(choices.at(i)) != std::string::npos) {
            myVectorOfCheckBox.at(i)->setCheck(true);
        }
    }

    // Add separator
    new FXHorizontalSeparator(this, GUIDesignHorizontalSeparator);

    // Create frame for buttons
    frameButtons = new FXHorizontalFrame(this, GUIDesignHorizontalFrame);

    // Create accept button
    myAcceptButton = new FXButton(frameButtons, "Accept", 0, this, FXDialogBox::ID_ACCEPT, GUIDesignButtonDialog);

    // Create cancel button
    myCancelButton = new FXButton(frameButtons, "Cancel", 0, this, FXDialogBox::ID_CANCEL, GUIDesignButtonDialog);

    // Create reset button
    myResetButton = new FXButton(frameButtons, "Reset", 0, this, MID_GNE_MODE_INSPECT_RESET, GUIDesignButtonDialog);

    // Execute dialog to make it modal, and if user press button "accept", save attribute
    if (execute()) {
        std::vector<std::string> attrSolution;
        // Iterate  over myVectorOfCheckBox
        for (int i = 0; i < (int)myVectorOfCheckBox.size(); i++) {
            // If checkBox is cheked, save attribute
            if (myVectorOfCheckBox.at(i)->getCheck()) {
                attrSolution.push_back(std::string(myVectorOfCheckBox.at(i)->getText().text()));
            }
        }
        // join to string
        myTextFieldAttr->setText(joinToString(attrSolution, " ").c_str());
        // Set attribute
        myAttrInputParent->onCmdSetAttribute(0, 0, 0);
    }
}
Ejemplo n.º 6
0
const std::string&
getVehicleClassNames(SVCPermissions permissions, bool expand) {
    if (permissions == SVCAll && !expand) {
        return vehicleClassNameAll;
    }
    // check if previously was cached
    if (getVehicleClassNamesCached.count(permissions) == 0) {
        getVehicleClassNamesCached[permissions] = joinToString(getVehicleClassNamesList(permissions), ' ');
    }
    return getVehicleClassNamesCached.at(permissions);
}
Ejemplo n.º 7
0
std::ostream& operator<<(std::ostream& os, const curfil::TrainingConfiguration& configuration) {
    os << "randomSeed: " << configuration.getRandomSeed() << std::endl;
    os << "samplesPerImage: " << configuration.getSamplesPerImage() << std::endl;
    os << "featureCount: " << configuration.getFeatureCount() << std::endl;
    os << "minSampleCount: " << configuration.getMinSampleCount() << std::endl;
    os << "maxDepth: " << configuration.getMaxDepth() << std::endl;
    os << "boxRadius: " << configuration.getBoxRadius() << std::endl;
    os << "regionSize: " << configuration.getRegionSize() << std::endl;
    os << "thresholds: " << configuration.getThresholds() << std::endl;
    os << "maxImages: " << configuration.getMaxImages() << std::endl;
    os << "imageCacheSize: " << configuration.getImageCacheSize() << std::endl;
    os << "accelerationMode: " << configuration.getAccelerationModeString() << std::endl;
    os << "maxSamplesPerBatch: " << configuration.getMaxSamplesPerBatch() << std::endl;
    os << "subsamplingType: " << configuration.getSubsamplingType() << std::endl;
    os << "useCIELab: " << configuration.isUseCIELab() << std::endl;
    os << "useDepthFilling: " << configuration.isUseDepthFilling() << std::endl;
    os << "deviceIds: " << joinToString(configuration.getDeviceIds()) << std::endl;
    os << "ignoredColors: " << joinToString(configuration.getIgnoredColors()) << std::endl;
    os << "useDepthImages: " << configuration.isUseDepthImages() << std::endl;
    os << "horizontalFlipping: " << configuration.doHorizontalFlipping() << std::endl;
    return os;
}
Ejemplo n.º 8
0
std::string
GNEVariableSpeedSignal::getAttribute(SumoXMLAttr key) const {
    switch (key) {
        case SUMO_ATTR_ID:
            return getAdditionalID();
        case SUMO_ATTR_LANES:
            return joinToString(getLaneChildIds(), " ");
        case SUMO_ATTR_POSITION:
            return toString(myPosition);
        case SUMO_ATTR_FILE:
            return myFilename;
        case GNE_ATTR_BLOCK_MOVEMENT:
            return toString(myBlocked);
        default:
            throw InvalidArgument(toString(getType()) + " attribute '" + toString(key) + "' not allowed");
    }
}
Ejemplo n.º 9
0
bool
NWWriter_SUMO::writeInternalNodes(OutputDevice& into, const NBNode& n) {
    bool ret = false;
    const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
    // build the list of internal lane ids
    std::vector<std::string> internalLaneIDs;
    for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
        const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
        for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
            if ((*k).toEdge != 0) {
                internalLaneIDs.push_back((*k).getInternalLaneID());
            }
        }
    }
    const std::vector<NBNode::Crossing>& crossings = n.getCrossings();
    for (std::vector<NBNode::Crossing>::const_iterator it_c = crossings.begin(); it_c != crossings.end(); ++it_c) {
        internalLaneIDs.push_back((*it_c).id + "_0");
    }
    // write the internal nodes
    for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
        const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
        for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
            if ((*k).toEdge == 0 || !(*k).haveVia) {
                continue;
            }
            Position pos = (*k).shape[-1];
            into.openTag(SUMO_TAG_JUNCTION).writeAttr(SUMO_ATTR_ID, (*k).viaID + "_0");
            into.writeAttr(SUMO_ATTR_TYPE, NODETYPE_INTERNAL);
            NWFrame::writePositionLong(pos, into);
            std::string incLanes = (*k).getInternalLaneID();
            if ((*k).foeIncomingLanes.length() != 0) {
                incLanes += " " + (*k).foeIncomingLanes;
            }
            into.writeAttr(SUMO_ATTR_INCLANES, incLanes);
            const std::vector<unsigned int>& foes = (*k).foeInternalLinks;
            std::vector<std::string> foeIDs;
            for (std::vector<unsigned int>::const_iterator it = foes.begin(); it != foes.end(); ++it) {
                foeIDs.push_back(internalLaneIDs[*it]);
            }
            into.writeAttr(SUMO_ATTR_INTLANES, joinToString(foeIDs, " "));
            into.closeTag();
            ret = true;
        }
    }
    return ret;
}
Ejemplo n.º 10
0
void
GNEVariableSpeedSignal::writeAdditional(OutputDevice& device, const std::string& currentDirectory) {
    // Write parameters
    device.openTag(getTag());
    device.writeAttr(SUMO_ATTR_ID, getID());
    device.writeAttr(SUMO_ATTR_LANES, joinToString(getLaneChildIds(), " ").c_str());
    device.writeAttr(SUMO_ATTR_X, myPosition.x());
    device.writeAttr(SUMO_ATTR_Y, myPosition.y());
    // If filenam isn't empty and save in filename is enabled, save in a different file. In other case, save in the same additional XML
    if (!myFilename.empty() && mySaveInFilename == true) {
        // Write filename attribute
        device.writeAttr(SUMO_ATTR_FILE, myFilename);
        // Save values in a different file
        OutputDevice& deviceVSS = OutputDevice::getDevice(currentDirectory + myFilename);
        deviceVSS.openTag("VSS");
        for (std::map<SUMOReal, SUMOReal>::const_iterator i = myVSSValues.begin(); i != myVSSValues.end(); ++i) {
            // Open VSS tag
            deviceVSS.openTag(SUMO_TAG_STEP);
            // Write TimeSTep
            deviceVSS.writeAttr(SUMO_ATTR_TIME, i->first);
            // Write speed
            deviceVSS.writeAttr(SUMO_ATTR_SPEED, i->second);
            // Close VSS tag
            deviceVSS.closeTag();
        }
        deviceVSS.close();
    } else {
        for (std::map<SUMOReal, SUMOReal>::const_iterator i = myVSSValues.begin(); i != myVSSValues.end(); ++i) {
            // Open VSS tag
            device.openTag(SUMO_TAG_STEP);
            // Write TimeSTep
            device.writeAttr(SUMO_ATTR_TIME, i->first);
            // Write speed
            device.writeAttr(SUMO_ATTR_SPEED, i->second);
            // Close VSS tag
            device.closeTag();
        }
    }
    if (myBlocked) {
        device.writeAttr(GNE_ATTR_BLOCK_MOVEMENT, myBlocked);
    }
    // Close tag
    device.closeTag();
}
Ejemplo n.º 11
0
std::string
GNEContainerStop::getAttribute(SumoXMLAttr key) const {
    switch (key) {
        case SUMO_ATTR_ID:
            return getAdditionalID();
        case SUMO_ATTR_LANE:
            return toString(myLane->getAttribute(SUMO_ATTR_ID));
        case SUMO_ATTR_STARTPOS:
            return toString(myStartPos);
        case SUMO_ATTR_ENDPOS:
            return toString(myEndPos);
        case SUMO_ATTR_LINES:
            return joinToString(myLines, " ");
        case GNE_ATTR_BLOCK_MOVEMENT:
            return toString(myBlocked);
        default:
            throw InvalidArgument(toString(getType()) + " attribute '" + toString(key) + "' not allowed");
    }
}
Ejemplo n.º 12
0
std::string
MSContainer::MSContainerStage_Driving::getStageDescription() const {
    return isWaiting4Vehicle() ? "waiting for " + joinToString(myLines, ",") : "transport";
}
Ejemplo n.º 13
0
std::string
Option_FloatVector::getValueString() const {
    return joinToString(myValue, ',');
}
Ejemplo n.º 14
0
unsigned int
NBNodeCont::joinJunctions(SUMOReal maxDist, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) {
    NodeClusters cands;
    NodeClusters clusters;
    generateNodeClusters(maxDist, cands);
    for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) {
        std::set<NBNode*> cluster = (*i);
        // remove join exclusions
        for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) {
            std::set<NBNode*>::iterator check = j;
            ++j;
            if (myJoinExclusions.count((*check)->getID()) > 0) {
                cluster.erase(check);
            }
        }
        // iteratively remove the fringe
        bool pruneFringe = true;
        while (pruneFringe) {
            pruneFringe = false;
            for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) {
                std::set<NBNode*>::iterator check = j;
                NBNode* n = *check;
                ++j;
                // remove geometry-like nodes at fringe of the cluster
                // (they have 1 neighbor in the cluster and at most 1 neighbor outside the cluster)
                std::set<NBNode*> neighbors;
                std::set<NBNode*> clusterNeigbors;
                for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) {
                    NBNode* neighbor = (*it_edge)->getToNode();
                    if (cluster.count(neighbor) == 0) {
                        neighbors.insert(neighbor);
                    } else {
                        clusterNeigbors.insert(neighbor);
                    }
                }
                for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) {
                    NBNode* neighbor = (*it_edge)->getFromNode();
                    if (cluster.count(neighbor) == 0) {
                        neighbors.insert(neighbor);
                    } else {
                        clusterNeigbors.insert(neighbor);
                    }
                }
                if (neighbors.size() <= 1 && clusterNeigbors.size() == 1) {
                    cluster.erase(check);
                    pruneFringe = true; // other nodes could belong to the fringe now
                }
            }
        }
        // exclude the fromNode of a long edge if the toNode is in the cluster (and they were both added via an alternative path).
        std::set<NBNode*> toRemove;
        for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end(); ++j) {
            NBNode* n = *j;
            const EdgeVector& edges = n->getOutgoingEdges();
            for (EdgeVector::const_iterator it_edge = edges.begin(); it_edge != edges.end(); ++it_edge) {
                NBEdge* edge = *it_edge;
                if (cluster.count(edge->getToNode()) != 0 && edge->getLoadedLength() > maxDist) {
                    //std::cout << "long edge " << edge->getID() << " (" << edge->getLoadedLength() << ", max=" << maxDist << ")\n";
                    toRemove.insert(n);
                    toRemove.insert(edge->getToNode());
                }
            }
        }
        for (std::set<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
            cluster.erase(*j);
        }
        if (cluster.size() > 1) {
            // check for clusters which are to complex and probably won't work very well
            // we count the incoming edges of the final junction
            std::set<NBEdge*> finalIncoming;
            std::set<NBEdge*> finalOutgoing;
            std::vector<std::string> nodeIDs;
            for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) {
                nodeIDs.push_back((*j)->getID());
                for (EdgeVector::const_iterator it_edge = (*j)->getIncomingEdges().begin(); it_edge != (*j)->getIncomingEdges().end(); ++it_edge) {
                    NBEdge* edge = *it_edge;
                    if (cluster.count(edge->getFromNode()) == 0) {
                        // incoming edge, does not originate in the cluster
                        finalIncoming.insert(edge);
                    }
                }
                for (EdgeVector::const_iterator it_edge = (*j)->getOutgoingEdges().begin(); it_edge != (*j)->getOutgoingEdges().end(); ++it_edge) {
                    NBEdge* edge = *it_edge;
                    if (cluster.count(edge->getToNode()) == 0) {
                        // outgoing edge, does not end in the cluster
                        finalOutgoing.insert(edge);
                    }
                }

            }
            if (finalIncoming.size() > 4) {
                std::sort(nodeIDs.begin(), nodeIDs.end());
                WRITE_WARNING("Not joining junctions " + joinToStringSorting(nodeIDs, ',') + " because the cluster is too complex (" + toString(finalIncoming.size()) + " incoming edges)");
            } else {
                // check for incoming parallel edges
                const SUMOReal PARALLEL_INCOMING_THRESHOLD = 10.0;
                bool foundParallel = false;
                for (std::set<NBEdge*>::const_iterator j = finalIncoming.begin(); j != finalIncoming.end() && !foundParallel; ++j) {
                    for (std::set<NBEdge*>::const_iterator k = finalIncoming.begin(); k != finalIncoming.end() && !foundParallel; ++k) {
                        if ((*j) != (*k) && fabs((*j)->getAngleAtNode((*j)->getToNode()) - (*k)->getAngleAtNode((*k)->getToNode())) < PARALLEL_INCOMING_THRESHOLD) {
                            std::vector<std::string> parallelEdgeIDs;
                            parallelEdgeIDs.push_back((*j)->getID());
                            parallelEdgeIDs.push_back((*k)->getID());
                            std::sort(parallelEdgeIDs.begin(), parallelEdgeIDs.end());
                            WRITE_WARNING("Not joining junctions " + joinToStringSorting(nodeIDs, ',') + " because the cluster is too complex (parallel incoming "
                                          + joinToString(parallelEdgeIDs, ',') + ")");
                            foundParallel = true;
                        }
                    }
                }
                // check for outgoing parallel edges
                for (std::set<NBEdge*>::const_iterator j = finalOutgoing.begin(); j != finalOutgoing.end() && !foundParallel; ++j) {
                    for (std::set<NBEdge*>::const_iterator k = finalOutgoing.begin(); k != finalOutgoing.end() && !foundParallel; ++k) {
                        if ((*j) != (*k) && fabs((*j)->getAngleAtNode((*j)->getFromNode()) - (*k)->getAngleAtNode((*k)->getFromNode())) < PARALLEL_INCOMING_THRESHOLD) {
                            std::vector<std::string> parallelEdgeIDs;
                            parallelEdgeIDs.push_back((*j)->getID());
                            parallelEdgeIDs.push_back((*k)->getID());
                            std::sort(parallelEdgeIDs.begin(), parallelEdgeIDs.end());
                            WRITE_WARNING("Not joining junctions " + joinToStringSorting(nodeIDs, ',') + " because the cluster is too complex (parallel outgoing "
                                          + joinToStringSorting(parallelEdgeIDs, ',') + ")");
                            foundParallel = true;
                        }
                    }
                }
                if (!foundParallel && cluster.size() > 1) {
                    // compute all connected components of this cluster
                    // (may be more than 1 if intermediate nodes were removed)
                    NodeClusters components;
                    for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end(); ++j) {
                        // merge all connected components into newComp
                        std::set<NBNode*> newComp;
                        NBNode* current = *j;
                        //std::cout << "checking connectivity for " << current->getID() << "\n";
                        newComp.insert(current);
                        for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end();) {
                            NodeClusters::iterator check = it_comp;
                            //std::cout << "   connected with " << toString(*check) << "?\n";
                            bool connected = false;
                            for (std::set<NBNode*>::iterator k = (*check).begin(); k != (*check).end(); ++k) {
                                if (current->getConnectionTo(*k) != 0 || (*k)->getConnectionTo(current) != 0) {
                                    //std::cout << "joining with connected component " << toString(*check) << "\n";
                                    newComp.insert((*check).begin(), (*check).end());
                                    it_comp = components.erase(check);
                                    connected = true;
                                    break;
                                }
                            }
                            if (!connected) {
                                it_comp++;
                            }
                        }
                        //std::cout << "adding new component " << toString(newComp) << "\n";
                        components.push_back(newComp);
                    }
                    for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end(); ++it_comp) {
                        if ((*it_comp).size() > 1) {
                            //std::cout << "adding cluster " << toString(*it_comp) << "\n";
                            clusters.push_back(*it_comp);
                        }
                    }
                }
            }
        }
    }
    joinNodeClusters(clusters, dc, ec, tlc);
    return (int)clusters.size();
}
Ejemplo n.º 15
0
std::string
getAllowedVehicleClassNames(SVCPermissions permissions) {
    return joinToString(getAllowedVehicleClassNamesList(permissions), ' ');
}
Ejemplo n.º 16
0
std::string
MSPerson::MSPersonStage_Driving::getStageTypeName() const {
    return isWaiting4Vehicle() ? "waiting for " + joinToString(myLines, ",") : "driving";
}
unsigned int
NBNodeCont::joinJunctions(SUMOReal maxdist, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) {
    NodeClusters cands;
    NodeClusters clusters;
    generateNodeClusters(maxdist, cands);
    for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) {
        std::set<NBNode*> cluster = (*i);
        // remove join exclusions
        for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) {
            std::set<NBNode*>::iterator check = j;
            ++j;
            if (myJoinExclusions.count((*check)->getID()) > 0) {
                cluster.erase(check);
            }
        }
        // iteratively remove the fringe
        bool pruneFringe = true;
        while (pruneFringe) {
            pruneFringe = false;
            for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) {
                std::set<NBNode*>::iterator check = j;
                NBNode* n = *check;
                ++j;
                // remove nodes with degree <= 2 at fringe of the cluster (at least one edge leads to a non-cluster node)
                if (
                    (n->getIncomingEdges().size() <= 1 && n->getOutgoingEdges().size() <= 1) &&
                    ((n->getIncomingEdges().size() == 0 ||
                      (n->getIncomingEdges().size() == 1 && cluster.count(n->getIncomingEdges()[0]->getFromNode()) == 0)) ||
                     (n->getOutgoingEdges().size() == 0 ||
                      (n->getOutgoingEdges().size() == 1 && cluster.count(n->getOutgoingEdges()[0]->getToNode()) == 0)))
                ) {
                    cluster.erase(check);
                    pruneFringe = true; // other nodes could belong to the fringe now
                }
            }
        }
        if (cluster.size() > 1) {
            // check for clusters which are to complex and probably won't work very well
            // we count the incoming edges of the final junction
            std::set<NBEdge*> finalIncoming;
            std::vector<std::string> nodeIDs;
            for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) {
                nodeIDs.push_back((*j)->getID());
                const EdgeVector& edges = (*j)->getIncomingEdges();
                for (EdgeVector::const_iterator it_edge = edges.begin(); it_edge != edges.end(); ++it_edge) {
                    NBEdge* edge = *it_edge;
                    if (cluster.count(edge->getFromNode()) == 0) {
                        // incoming edge, does not originate in the cluster
                        finalIncoming.insert(edge);
                    }
                }

            }
            if (finalIncoming.size() > 4) {
                WRITE_WARNING("Not joining junctions " + joinToString(nodeIDs, ',') + " because the cluster is too complex");
            } else {
                clusters.push_back(cluster);
            }
        }
    }
    joinNodeClusters(clusters, dc, ec, tlc);
    return (int)clusters.size();
}