/** * このシードを使って、PM方式で道路生成する。 * パッチが使えないケースに使用される。 * 通常、パッチ間の接着剤として使いたいなぁ。。。 */ void PatchRoadGenerator::attemptExpansion2(int roadType, RoadVertexDesc srcDesc, ExFeature& f, std::list<RoadVertexDesc> &seeds) { float length = 0.0f; if (roadType == RoadEdge::TYPE_AVENUE) { length = f.avgAvenueLength; } else { length = f.avgStreetLength; } float roadAngleTolerance = G::getFloat("roadAngleTolerance"); std::vector<RoadEdgePtr> edges; // 当該頂点から出るエッジをリストアップし、基底の方向を決定する float direction = 0.0f; { RoadOutEdgeIter ei, eend; for (boost::tie(ei, eend) = boost::out_edges(srcDesc, roads.graph); ei != eend; ++ei) { if (!roads.graph[*ei]->valid) continue; Polyline2D polyline = GraphUtil::orderPolyLine(roads, *ei, srcDesc); QVector2D vec = polyline[1] - polyline[0]; direction = atan2f(vec.y(), vec.x()); break; } } // 既にあるエッジと正反対の方向を計算 direction += 3.141592653; // ものすごい近くに、他の頂点がないかあれば、そことコネクトして終わり。 // それ以外の余計なエッジは生成しない。さもないと、ものすごい密度の濃い道路網になっちゃう。 { RoadVertexDesc nearestDesc; if (GraphUtil::getVertexExceptDeadend(roads, srcDesc, length, direction, 0.3f, nearestDesc)) { // もし、既にエッジがあるなら、キャンセル if (GraphUtil::hasEdge(roads, srcDesc, nearestDesc)) return; RoadEdgePtr e = RoadEdgePtr(new RoadEdge(roadType, 1)); e->polyline.push_back(roads.graph[srcDesc]->pt); e->polyline.push_back(roads.graph[nearestDesc]->pt); if (!GraphUtil::isIntersect(roads, e->polyline)) { RoadEdgeDesc e_desc = GraphUtil::addEdge(roads, srcDesc, nearestDesc, e); return; } } } // 近くにエッジがあれば、コネクト { RoadVertexDesc nearestDesc; RoadEdgeDesc nearestEdgeDesc; QVector2D intPoint; if (GraphUtil::getCloseEdge(roads, srcDesc, length, direction, 0.3f, nearestEdgeDesc, intPoint)) { // エッジにスナップ nearestDesc = GraphUtil::splitEdge(roads, nearestEdgeDesc, intPoint); roads.graph[nearestDesc]->properties["generation_type"] = "snapped"; roads.graph[nearestDesc]->properties["group_id"] = roads.graph[nearestEdgeDesc]->properties["group_id"]; roads.graph[nearestDesc]->properties["ex_id"] = roads.graph[nearestEdgeDesc]->properties["ex_id"]; roads.graph[nearestDesc]->properties.remove("example_desc"); RoadEdgePtr e = RoadEdgePtr(new RoadEdge(roadType, 1)); e->polyline.push_back(roads.graph[srcDesc]->pt); e->polyline.push_back(roads.graph[nearestDesc]->pt); RoadEdgeDesc e_desc = GraphUtil::addEdge(roads, srcDesc, nearestDesc, e); return; } } // ものすごい近くに、他の頂点がないかあれば、そことコネクトして終わり。 // それ以外の余計なエッジは生成しない。さもないと、ものすごい密度の濃い道路網になっちゃう。 { RoadVertexDesc nearestDesc; if (GraphUtil::getVertexExceptDeadend(roads, srcDesc, length, direction, 1.5f, nearestDesc)) { // もし、既にエッジがあるなら、キャンセル if (GraphUtil::hasEdge(roads, srcDesc, nearestDesc)) return; RoadEdgePtr e = RoadEdgePtr(new RoadEdge(roadType, 1)); e->polyline.push_back(roads.graph[srcDesc]->pt); e->polyline.push_back(roads.graph[nearestDesc]->pt); if (!GraphUtil::isIntersect(roads, e->polyline)) { RoadEdgeDesc e_desc = GraphUtil::addEdge(roads, srcDesc, nearestDesc, e); return; } } } // 道路生成用のカーネルを合成する synthesizeItem(roadType, srcDesc, length, edges); float z = vboRenderManager->getTerrainHeight(roads.graph[srcDesc]->pt.x(), roads.graph[srcDesc]->pt.y(), true); int cnt = 0; for (int i = 0; i < edges.size(); ++i) { if (RoadGeneratorHelper::isRedundantEdge(roads, srcDesc, edges[i]->polyline, roadAngleTolerance)) continue; if (growRoadSegment(roadType, srcDesc, f, edges[i]->polyline, edges[i]->lanes, roadAngleTolerance, seeds)) { cnt++; } // hack: to avoid creating an intersection on the river. if (roadType == RoadEdge::TYPE_AVENUE && z < G::getFloat("seaLevelForStreet")) { if (cnt >= 1) break; } } }

void GLGameModel::create() { GLuint currentTex = 65535; TextureManager *tm = GAME->getTextureManager(); glNewList(displayListID, GL_COMPILE); if(getIsLightingEnabled()) glEnable(GL_LIGHTING); for(int i = 0; i < glModelFaces.size(); ++i) { GLModelFace face = glModelFaces.at(i); // set or unset texture if neccessary if(!face.materialName.isEmpty() && materials.contains(face.materialName)) { QString textureFileName = materials.value(face.materialName); GLuint texId = tm->getTextureId(textureFileName); if(currentTex != texId) { glDisable(GL_COLOR_MATERIAL); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texId); GAME->getGLWidget()->qglColor(Qt::white); currentTex = texId; } } else { if(currentTex != 0) { glEnable(GL_COLOR_MATERIAL); currentTex = 0; glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); } } // draw the model glBegin(GL_POLYGON); for(int n = 0; n < face.vertexIds.size(); ++n) { int x = face.vertexIds.at(n); if(x < 0 || x >= vertices.size()) continue; QVector3D v = vertices.at(x); if(n < face.textureCoordIds.size() && currentTex > 0) { x = face.textureCoordIds.at(n); QVector2D vt = textureCoords.at(x); glTexCoord2f(vt.x(), vt.y()); } if(n < face.vertexNormalIds.size()) { x = face.vertexNormalIds.at(n); QVector3D vn = vertexNormals.at(x); glNormal3f(vn.x(), vn.y(), vn.z()); } glVertex3f(v.x(), v.y(), v.z()); } glEnd(); } glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glEndList(); createFrame(); created = true; }

/** * エッジABと頂点Cの距離を計算して返却する。さらに、エッジAB上で最も頂点Cに近い点をclosestPtInABに格納する。 */ float Util::pointSegmentDistanceXY(const QVector2D& a, const QVector2D& b, const QVector2D& c, QVector2D& closestPtInAB) { float dist; float r_numerator = (c.x()-a.x())*(b.x()-a.x()) + (c.y()-a.y())*(b.y()-a.y()); float r_denomenator = (b.x()-a.x())*(b.x()-a.x()) + (b.y()-a.y())*(b.y()-a.y()); float r = r_numerator / r_denomenator; // float px = a.x() + r*(b.x()-a.x()); float py = a.y() + r*(b.y()-a.y()); // float s = ((a.y()-c.y())*(b.x()-a.x())-(a.x()-c.x())*(b.y()-a.y()) ) / r_denomenator; float distanceLine = fabs(s)*sqrt(r_denomenator); // エッジAB上で最も頂点Cに近い点をclosestPtInABに格納する。 closestPtInAB.setX(px); closestPtInAB.setY(py); if ((r >= 0) && (r <= 1)) { dist = distanceLine; } else { float dist1 = (c.x()-a.x())*(c.x()-a.x()) + (c.y()-a.y())*(c.y()-a.y()); float dist2 = (c.x()-b.x())*(c.x()-b.x()) + (c.y()-b.y())*(c.y()-b.y()); if (dist1 < dist2) { dist = sqrt(dist1); } else { dist = sqrt(dist2); } } return abs(dist); }

/*! Constructs a 3D vector from the specified 2D \a vector. The z coordinate is set to \a zpos. \sa toVector2D() */ QVector3DD::QVector3DD(const QVector2D& vector, double zpos) { xp = vector.x(); yp = vector.y(); zp = zpos; }

void TMSIImpedanceWidget::addElectrodeItem(QString electrodeName, QVector2D position) { TMSIElectrodeItem *item = new TMSIElectrodeItem(electrodeName, QPointF(position.x(), position.y()), QColor(m_cbColorMap->valueToJet(1)), m_qmElectrodeNameIndex[electrodeName]); item->setPos(QPointF(position.x(), position.y())); m_qGScene->addItem(item); }

candidates << Candidate(QVector2D(rect.topRight() - rect.topLeft()), QPointF(0.0, 0.0), SideTop) << Candidate(QVector2D(rect.topLeft() - rect.topRight()), rect.topRight() - rect.topLeft(), SideTop) << Candidate(QVector2D(rect.bottomLeft() - rect.topLeft()), QPointF(0.0, 0.0), SideLeft) << Candidate(QVector2D(rect.topLeft() - rect.bottomLeft()), rect.bottomLeft() - rect.topLeft(), SideLeft) << Candidate(QVector2D(rect.bottomRight() - rect.bottomLeft()), rect.bottomLeft() - rect.topLeft(), SideBottom) << Candidate(QVector2D(rect.bottomLeft() - rect.bottomRight()), rect.bottomRight() - rect.topLeft(), SideBottom) << Candidate(QVector2D(rect.bottomRight() - rect.topRight()), rect.topRight() - rect.topLeft(), SideRight) << Candidate(QVector2D(rect.topRight() - rect.bottomRight()), rect.bottomRight() - rect.topLeft(), SideRight); QVector<QVector2D> rectEdgeVectors; rectEdgeVectors << QVector2D(rect.topLeft() - rect.topLeft()) << QVector2D(rect.topRight() - rect.topLeft()) << QVector2D(rect.bottomLeft() - rect.topLeft()) << QVector2D(rect.bottomRight() -rect.topLeft()); QVector2D directionVector(line.p2() - line.p1()); directionVector.normalize(); QVector2D sideVector(directionVector.y(), -directionVector.x()); QVector2D intersectionVector(intersectionLine.p2() - intersectionLine.p1()); intersectionVector.normalize(); QVector2D outsideVector = QVector2D(intersectionVector.y(), -intersectionVector.x()); double p = QVector2D::dotProduct(directionVector, outsideVector); if (p < 0.0) outsideVector = outsideVector * -1.0; double smallestA = -1.0; QPointF rectTranslation; Side side = SideUnspecified;

void PaintData::setScale(const QVector2D &scale) { d->scale.setXScale(scale.x()); d->scale.setYScale(scale.y()); }

/** * オリジナルの座標系での頂点座標v1とv2を通る直線を、縮尺された座標系のhtSpace上に描画する。 */ void HoughTransform::line(const QVector2D& p1, const QVector2D& p2, float sigma) { QVector2D v1 = (p1 - bbox.minPt) * scale; QVector2D v2 = (p2 - bbox.minPt) * scale; QVector2D vl, vr; if (v1.x() < v2.x()) { vl = v1; vr = v2; } else { vl = v2; vr = v1; } QVector2D vu, vd; if (v1.y() < v2.y()) { vd = v1; vu = v2; } else { vd = v2; vu = v1; } QVector2D dir = v2 - v1; float len = dir.length(); sigma *= scale; float sigma2 = SQR(sigma); if (fabs(dir.x()) > fabs(dir.y())) { for (int x = 0; x < htSpace.cols; x++) { int y = dir.y() * ((float)x - v1.x()) / dir.x() + v1.y() + 0.5f; if (y < 0 || y >= htSpace.rows) continue; float h = 0; if (x >= vl.x() && x <= vr.x()) { h = len; } else if (x < vl.x()) { h = len * expf(-(SQR(x - vl.x()) + SQR(y - vl.y())) * 0.5f / sigma2); } else { h = len * expf(-(SQR(x - vr.x()) + SQR(y - vr.y())) * 0.5f / sigma2); } htSpace.at<float>(y, x) += h; } } else { for (int y = 0; y < htSpace.rows; y++) { int x = dir.x() * ((float)y - v1.y()) / dir.y() + v1.x() + 0.5f; if (x < 0 || x >= htSpace.cols) continue; float h = 0; if (y >= vd.y() && y <= vu.y()) { h = len; } else if (y < vd.y()) { h = len * expf(-(SQR(x - vd.x()) + SQR(y - vd.y())) * 0.5f / sigma2); } else { h = len * expf(-(SQR(x - vu.x()) + SQR(y - vu.y())) * 0.5f / sigma2); } htSpace.at<float>(y, x) += h; } } }

//TODO This function is relatively slow because of many hashtable lookups // in HydroFile class. Consider pros and cons of using a grid instead. void River::setCurrentHydroFile(HydroFile *newHydroFile) { // TODO Get rid of max_vector_component and g.COMPARE_MAX double max_vector_component = 0.0; for (int i = 0; i < p.getSize(); i++ ) { int x = p.pxcor[i]; int y = p.pycor[i]; if(newHydroFile->patchExists(x,y)){ double depth = newHydroFile->getDepth(x,y); QVector2D flowVector = newHydroFile->getVector(x,y); double flowX = flowVector.x(); double flowY = flowVector.y(); //TODO Replace this line with flowVector.length() once we know if it is correct to do so. double flowMagnitude = newHydroFile->getFileVelocity(x,y); p.hasWater[i] = true; p.depth[i] = depth; p.flowX[i] = flowX; p.flowY[i] = flowY; p.flowMagnitude[i] = flowMagnitude; if (max_vector_component < fabs(flowX) ) { max_vector_component = fabs(flowX); } if( max_vector_component < fabs(flowY)) { max_vector_component = fabs(flowY); } } else { p.hasWater[i] = false; p.depth[i] = 0.0; p.flowX[i] = 0.0; p.flowY[i] = 0.0; p.flowMagnitude[i] = 0.0; } // update miscellanous variables inside the patch double current_depth = 0.0; if(currHydroFile != NULL && currHydroFile->patchExists(x,y)){ current_depth = currHydroFile->getDepth(x,y); } // Water -> Land if (current_depth > 0.0 && p.depth[i] == 0.0) { p.detritus[i] += p.DOC[i] + p.POC[i] + p.phyto[i] + p.macro[i] + p.waterdecomp[i] + p.seddecomp[i] + p.herbivore[i] + p.sedconsumer[i] + p.consumer[i]; p.DOC[i] = 0.0; p.POC[i] = 0.0; p.phyto[i] = 0.0; p.macro[i] = 0.0; p.waterdecomp[i] = 0.0; p.seddecomp[i] = 0.0; p.herbivore[i] = 0.0; p.sedconsumer[i] = 0.0; p.consumer[i] = 0.0; } // Land -> Water if (current_depth == 0.0 && p.depth[i] > 0.0) { p.detritus[i] *= 0.5; } } // update the maximum vector for the timestep g.COMPARE_MAX = max_vector_component; currHydroFile = newHydroFile; }

inline QVector2D CFruchtermanReingold::CoulombForce(const int firstVertexIndex, const int secondVertexIndex) const { QVector2D direction = QVector2D(vgc_vertices[firstVertexIndex].v_coordinates - vgc_vertices[secondVertexIndex].v_coordinates); return vgc_coeff * vgc_coeff / Distance(vgc_vertices[firstVertexIndex].v_coordinates, vgc_vertices[secondVertexIndex].v_coordinates) * direction.normalized(); }

inline QVector2D CFruchtermanReingold::HookeForce(const int firstVertexIndex, const int secondVertexIndex) const { QVector2D direction = QVector2D(vgc_vertices[secondVertexIndex].v_coordinates - vgc_vertices[firstVertexIndex].v_coordinates); return (SPRING_CONSTANT / vgc_coeff) * (Distance(vgc_vertices[firstVertexIndex].v_coordinates, vgc_vertices[secondVertexIndex].v_coordinates) / SPRING_LENGTH) * direction.normalized(); }

QT_BEGIN_NAMESPACE /*! \class QTriangle3D \brief The QTriangle3D class represents a triangle as three points in 3D space. \since 4.8 \ingroup qt3d \ingroup qt3d::math A triangle is defined by 3 points in 3D space. Since any 3 points define a plane, the triangle can be thought of as defining a plane, and forming a geometric region in that plane. If you need a simple plane, with no particular geometry, then QPlane3D is a more compact and mathematically sufficient class. The three points are labelled p(), q() and r() for consistency with textbook treatments. It is recommended that the points be supplied in counter-clockwise order for correct orientation of the triangle's plane(). \sa QPlane3D */ /*! \fn QTriangle3D::QTriangle3D() Constructs a default triangle which lies in the x-z plane, with the three vertices (0, 0, 0), (1, 0, 0), and (0, 1, 0). */ /*! \fn QTriangle3D::QTriangle3D(const QVector3D &p, const QVector3D &q, const QVector3D &r) Constructs a triangle with the supplied \a p, \a q and \a r vertices. */ /*! \fn QVector3D QTriangle3D::p() const Returns the value of the P vertex on the triangle. \sa q(), r(), setP() */ /*! \fn void QTriangle3D::setP(const QVector3D &point) Sets the value of the P vertex on the triangle to \a point. \sa setQ(), setR(), p() */ /*! \fn QVector3D QTriangle3D::q() const Returns the value of the Q vertex on the triangle. \sa p(), r(), setQ() */ /*! \fn void QTriangle3D::setQ(const QVector3D &point) Sets the value of the Q vertex on the triangle \a point. \sa setP(), setR(), q() */ /*! \fn QVector3D QTriangle3D::r() const Returns the value of the R vertex on the triangle. \sa p(), q(), setR() */ /*! \fn void QTriangle3D::setR(const QVector3D &point) Sets the value of the R vertex on the triangle \a point. \sa setP(), setQ(), r() */ /*! \fn QPlane3D QTriangle3D::plane() const Returns the plane in which the triangle lies. \sa QPlane3D */ /*! \fn QVector3D QTriangle3D::center() const Returns the center of the triangle, which is the geometric average of the three vertices. */ /*! \fn QVector3D QTriangle3D::faceNormal() const Returns the vector normal to this triangle, computed from the cross-product of P-Q and Q-R. The result is not normalized. */ /*! Returns true if this triangle contains \a point; false otherwise. To contain the \a point means that: \list \o the point lies on the same plane as the triangle, and \o the point \list \o lies either wholly within the triangle, or \o lies on one of the sides, or \o coincides with one of the 3 vertices \endlist \endlist \sa intersects() */ bool QTriangle3D::contains(const QVector3D &point) const { // Check if the point is on the triangle's plane first. QVector3D normal = QVector3D::crossProduct(m_q - m_p, m_r - m_q); if (!qFuzzyIsNull(float(QVector3D::dotProduct(normal, m_p - point)))) return false; // Compute the barycentric co-ordinates and use them to determine // if the point is within the triangle. QVector2D c = uv(point); if (c.x() < 0.0f || c.x() > 1.0f) return false; if (c.y() < 0.0f || c.y() > 1.0f) return false; if ((c.x() + c.y()) > 1.0f) return false; return true; }

/*! \internal Draws the line ending with the specified \a painter at the position \a pos. The direction of the line ending is controlled with \a dir. */ void QCPLineEnding::draw(QCPPainter *painter, const QVector2D &pos, const QVector2D &dir) const { if (mStyle == esNone) return; QVector2D lengthVec(dir.normalized()); if (lengthVec.isNull()) lengthVec = QVector2D(1, 0); QVector2D widthVec(-lengthVec.y(), lengthVec.x()); lengthVec *= (float)(mLength*(mInverted ? -1 : 1)); widthVec *= (float)(mWidth*0.5*(mInverted ? -1 : 1)); QPen penBackup = painter->pen(); QBrush brushBackup = painter->brush(); QPen miterPen = penBackup; miterPen.setJoinStyle(Qt::MiterJoin); // to make arrow heads spikey QBrush brush(painter->pen().color(), Qt::SolidPattern); switch (mStyle) { case esNone: break; case esFlatArrow: { QPointF points[3] = {pos.toPointF(), (pos-lengthVec+widthVec).toPointF(), (pos-lengthVec-widthVec).toPointF() }; painter->setPen(miterPen); painter->setBrush(brush); painter->drawConvexPolygon(points, 3); painter->setBrush(brushBackup); painter->setPen(penBackup); break; } case esSpikeArrow: { QPointF points[4] = {pos.toPointF(), (pos-lengthVec+widthVec).toPointF(), (pos-lengthVec*0.8f).toPointF(), (pos-lengthVec-widthVec).toPointF() }; painter->setPen(miterPen); painter->setBrush(brush); painter->drawConvexPolygon(points, 4); painter->setBrush(brushBackup); painter->setPen(penBackup); break; } case esLineArrow: { QPointF points[3] = {(pos-lengthVec+widthVec).toPointF(), pos.toPointF(), (pos-lengthVec-widthVec).toPointF() }; painter->setPen(miterPen); painter->drawPolyline(points, 3); painter->setPen(penBackup); break; } case esDisc: { painter->setBrush(brush); painter->drawEllipse(pos.toPointF(), mWidth*0.5, mWidth*0.5); painter->setBrush(brushBackup); break; } case esSquare: { QVector2D widthVecPerp(-widthVec.y(), widthVec.x()); QPointF points[4] = {(pos-widthVecPerp+widthVec).toPointF(), (pos-widthVecPerp-widthVec).toPointF(), (pos+widthVecPerp-widthVec).toPointF(), (pos+widthVecPerp+widthVec).toPointF() }; painter->setPen(miterPen); painter->setBrush(brush); painter->drawConvexPolygon(points, 4); painter->setBrush(brushBackup); painter->setPen(penBackup); break; } case esDiamond: { QVector2D widthVecPerp(-widthVec.y(), widthVec.x()); QPointF points[4] = {(pos-widthVecPerp).toPointF(), (pos-widthVec).toPointF(), (pos+widthVecPerp).toPointF(), (pos+widthVec).toPointF() }; painter->setPen(miterPen); painter->setBrush(brush); painter->drawConvexPolygon(points, 4); painter->setBrush(brushBackup); painter->setPen(penBackup); break; } case esBar: { painter->drawLine((pos+widthVec).toPointF(), (pos-widthVec).toPointF()); break; } case esHalfBar: { painter->drawLine((pos+widthVec).toPointF(), pos.toPointF()); break; } case esSkewedBar: { if (qFuzzyIsNull(painter->pen().widthF()) && !painter->modes().testFlag(QCPPainter::pmNonCosmetic)) { // if drawing with cosmetic pen (perfectly thin stroke, happens only in vector exports), draw bar exactly on tip of line painter->drawLine((pos+widthVec+lengthVec*0.2f*(mInverted?-1:1)).toPointF(), (pos-widthVec-lengthVec*0.2f*(mInverted?-1:1)).toPointF()); } else { // if drawing with thick (non-cosmetic) pen, shift bar a little in line direction to prevent line from sticking through bar slightly painter->drawLine((pos+widthVec+lengthVec*0.2f*(mInverted?-1:1)+dir.normalized()*qMax(1.0f, (float)painter->pen().widthF())*0.5f).toPointF(), (pos-widthVec-lengthVec*0.2f*(mInverted?-1:1)+dir.normalized()*qMax(1.0f, (float)painter->pen().widthF())*0.5f).toPointF()); } break; } } }

/** * 指定されたtensor filedに基づいて、ptからsegment_length分の道路セグメントを生成する。 * ただし、ターゲットエリア外に出るか、既存セグメントとの交差点が既存交差点の近くなら、途中で終了する。 * * @param tensor tensor field * @param segment_length segment length * @param near_threshold near threshold * @param srcDesc src vertex desc * @param tgtDesc [OUT] tgt vertex desc * @param type 1 -- major eigen vector / 2 -- minor eigen vector * @return 0 -- 正常終了 / 1 -- ターゲットエリア外に出て終了 / 2 -- 既存交差点の近くで交差して終了 */ int PMRoadGenerator::generateRoadSegmentByTensor(const cv::Mat& tensor, float segment_length, float near_threshold, RoadVertexDesc srcDesc, RoadVertexDesc& tgtDesc, int type) { int num_step = 5; float step_length = (segment_length + Util::genRand(-1.0, 1.0)) / num_step; BBox bbox = targetArea.envelope(); QVector2D pt = roads.graph[srcDesc]->pt; RoadEdgePtr new_edge = RoadEdgePtr(new RoadEdge(RoadEdge::TYPE_AVENUE, 1)); new_edge->addPoint(pt); for (int i = 0; i < num_step; ++i) { // ターゲットエリア外ならストップ if (!targetArea.contains(pt)) { return 1; } ///////////////////////////////////////////////////////////////////// // use Runge-Kutta 4 to obtain the next angle int c = pt.x() - bbox.minPt.x(); int r = pt.y() - bbox.minPt.y(); float angle1 = tensor.at<float>(r, c); if (type == 2) angle1 += M_PI / 2; // minor eigen vectorならPI/2を足す // angle2 QVector2D pt2 = pt + QVector2D(cosf(angle1), sinf(angle1)) * (step_length * 0.5); int c2 = pt2.x() - bbox.minPt.x(); int r2 = pt2.y() - bbox.minPt.y(); float angle2 = angle1; if (c2 >= 0 && c2 < tensor.cols && r2 >= 0 && r2 < tensor.rows) { angle2 = tensor.at<float>(r2, c2); if (type == 2) angle2 += M_PI / 2; // minor eigen vectorならPI/2を足す } // angle3 QVector2D pt3 = pt + QVector2D(cosf(angle2), sinf(angle2)) * (step_length * 0.5); int c3 = pt3.x() - bbox.minPt.x(); int r3 = pt3.y() - bbox.minPt.y(); float angle3 = angle2; if (c3 >= 0 && c3 < tensor.cols && r3 >= 0 && r3 < tensor.rows) { angle3 = tensor.at<float>(r3, c3); if (type == 2) angle3 += M_PI / 2; // minor eigen vectorならPI/2を足す } // angle4 QVector2D pt4 = pt + QVector2D(cosf(angle3), sinf(angle3)) * step_length; int c4 = pt4.x() - bbox.minPt.x(); int r4 = pt4.y() - bbox.minPt.y(); float angle4 = angle3; if (c4 >= 0 && c4 < tensor.cols && r4 >= 0 && r4 < tensor.rows) { angle4 = tensor.at<float>(r4, c4); if (type == 2) angle4 += M_PI / 2; // minor eigen vectorならPI/2を足す } // RK4によりangleを計算 float angle = angle1 / 6.0 + angle2 / 3.0 + angle3 / 3.0 + angle4 / 6.0; // 次のステップの座標を求める QVector2D next_pt = pt + QVector2D(cosf(angle), sinf(angle)) * step_length; // 交差点を求める RoadEdgeDesc nearestEdgeDesc; QVector2D intPt; if (GraphUtil::isIntersect(roads, pt, next_pt, nearestEdgeDesc, intPt)) { int edgeEigenType = roads.graph[nearestEdgeDesc]->eigenType; // 他のエッジにスナップ tgtDesc = GraphUtil::splitEdge(roads, nearestEdgeDesc, intPt); intPt = roads.graph[tgtDesc]->pt; roads.graph[tgtDesc]->eigenType |= type; roads.graph[tgtDesc]->eigenType |= edgeEigenType; roads.graph[tgtDesc]->new_vertx = true; new_edge->addPoint(intPt); // エッジを生成 new_edge->eigenType = type; GraphUtil::addEdge(roads, srcDesc, tgtDesc, new_edge); // エッジを交差点から再開させる srcDesc = tgtDesc; pt = intPt; new_edge = RoadEdgePtr(new RoadEdge(RoadEdge::TYPE_AVENUE, 1)); new_edge->addPoint(pt); // 既に近くに頂点がないかチェック bool foundNearVertex = false; RoadVertexIter vi, vend; for (boost::tie(vi, vend) = boost::vertices(roads.graph); vi != vend; ++vi) { // 現在生成中の道路セグメントは、チェックしない。 if (roads.graph[*vi]->new_vertx) continue; // major vector と minor vectorで異なる場合は、チェックしない if (!(roads.graph[*vi]->eigenType & type)) continue; float dist = (roads.graph[*vi]->pt - intPt).length(); if (dist < near_threshold) { foundNearVertex = true; break; } } if (foundNearVertex) { // 道路セグメントの生成を交差点でストップさせる return 2; } } // ターゲットエリア外なら、終了 if (!targetArea.contains(next_pt)) { return 1; } new_edge->addPoint(next_pt); pt = next_pt; } if (new_edge->getLength() >= 1.0f) { RoadVertexPtr v = RoadVertexPtr(new RoadVertex(pt)); tgtDesc = GraphUtil::addVertex(roads, v); roads.graph[tgtDesc]->eigenType = type; roads.graph[tgtDesc]->new_vertx = true; // add edge new_edge->eigenType = type; GraphUtil::addEdge(roads, srcDesc, tgtDesc, new_edge); } else { tgtDesc = srcDesc; } return 0; }

QVector2D Graph::nodeToGraph(QVector2D node) { QVector2D ret; ret.setX(nodeToGraphX(node.x())); ret.setY(nodeToGraphY(node.y())); return ret; }

//TODO Use QFile int River::saveCSV(QString displayedStock, int daysElapsed) const { QString file_name = "./results/data/map_data_"; QDateTime date_time = QDateTime::currentDateTime(); QString date_time_str = date_time.toString("MMM_d_H_mm_ss"); file_name.append(date_time_str); file_name.append(".csv"); const char* cfile_name = file_name.toStdString().c_str(); FILE* f = fopen(cfile_name, "w"); if (f == NULL) { printf("file name: %s could not be opened\n", cfile_name); return 0; } // GUI variables used fprintf(f,"%s\n","# timestep_factor,hydro_group,days_to_run,tss,k_phyto,k_macro,sen_macro_coef,resp_macro_coef,macro_base_temp,macro_mass_max,macro_vel_max,gross_macro_coef,which_stock"); fprintf(f,"%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%s\n", config.timestep, daysElapsed, config.tss, config.kPhyto, config.kMacro, (config.macroSenescence/24), (config.macroRespiration/24), config.macroTemp, config.macroMassMax, config.macroVelocityMax, config.macroGross, displayedStock.toStdString().c_str()); //TODO Print out the hydrofile used for this simulated day. fprintf(f,"%s\n","# pxcor,pycor,pcolor,px_vector,py_vector,depth,velocity,assimilation,detritus,DOC,POC,waterdecomp,seddecomp,macro,phyto,herbivore,sedconsumer,peri,consumer"); int x,y; int pxcor, pycor, pcolor; double px_vector, py_vector; double depth; double velocity; double assimilation; double detritus, DOC, POC, waterdecomp, seddecomp, macro, phyto, herbivore, sedconsumer, peri, consumer; for(x = 0; x < width; x++) { for(y=0;y < height; y++) { //Skip if cell doesn't exist or is land if( !currHydroFile->patchExists(x,y) || currHydroFile->getDepth(x,y) <= 0.0 ) { continue; } depth = currHydroFile->getDepth(x,y); QVector2D flowVector = currHydroFile->getVector(x,y); velocity = currHydroFile->getFileVelocity(x,y); int i = p.getIndex(x,y); pxcor = p.pxcor[i]; pycor = p.pycor[i]; pcolor = p.pcolor[i]; px_vector = flowVector.x(); py_vector = flowVector.y(); assimilation = p.assimilation[i]; detritus = p.detritus[i]; DOC = p.DOC[i]; POC = p.POC[i]; waterdecomp = p.waterdecomp[i]; seddecomp = p.seddecomp[i]; macro = p.macro[i]; phyto = p.phyto[i]; herbivore = p.herbivore[i]; sedconsumer = p.sedconsumer[i]; peri = p.peri[i]; consumer = p.consumer[i]; fprintf(f,"%d,%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n",pxcor,pycor,pcolor,px_vector,py_vector,depth, velocity,assimilation,detritus,DOC,POC, waterdecomp,seddecomp,macro,phyto,herbivore,sedconsumer,peri,consumer); } } fclose(f); return 1; }

QPixmap ContainerSVG::pixmap(const Image &image, const QSize &size, const AspectRatioMode &mode) { #ifdef IMAGEMAP_DEBUG wzLog(LOG_IM) << "\tContainer:" << m_filename; wzLog(LOG_IM) << "\tMode:" << mode; wzLog(LOG_IM) << "\tType:" << image.type; #endif if (image.type == FixedType) { QVector2D factors = calculateFactors_(size, image.size, mode); #ifdef IMAGEMAP_DEBUG wzLog(LOG_IM) << "\tFactors:" << factors; wzLog(LOG_IM) << "\tSize:" << qRound(image.size.width() * factors.x()) << qRound(image.size.height() * factors.y()); wzLog(LOG_IM) << "\tPosition:" << qRound(image.xPosition * factors.x()) << qRound(image.yPosition * factors.y()); #endif // Creates a full scaled copy of the container image with the factors. QPixmap full = createScaledContainer_(factors); // Extracts the image. QPixmap result = full.copy(qRound(image.xPosition * factors.x()), qRound(image.yPosition * factors.y()), qRound(image.size.width() * factors.x()), qRound(image.size.height() * factors.y())); return result; } else { if (!m_renderer->elementExists(image.name)) { m_map->setError(1, QString("Image \"%1\" not found in container \"%2\"") .arg(image.name).arg(m_filename)); return QPixmap(); } QRectF bounds = m_renderer->boundsOnElement(image.name); QVector2D factors = calculateFactors_(size, bounds.size().toSize(), mode); #ifdef IMAGEMAP_DEBUG wzLog(LOG_IM) << "\tSVG ID:" << image.name; wzLog(LOG_IM) << "\tSVG Size:" << bounds.size(); wzLog(LOG_IM) << "\tFactors:" << factors; wzLog(LOG_IM) << "\tSize:" << qRound(image.size.width() * factors.x()) << qRound(image.size.height() * factors.y()); wzLog(LOG_IM) << "\tPosition:" << qRound(image.xPosition * factors.x()) << qRound(image.yPosition * factors.y()); #endif QSize mySize(qRound(bounds.width() * factors.x()), qRound(bounds.height() * factors.y())); QPixmap result(mySize); result.fill(Qt::transparent); QPainter pixPainter(&result); pixPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true); m_renderer->render(&pixPainter, image.name); pixPainter.end(); return result; } }

void Fill::neighbourCheck(QVector2D pos) { int lw = lvl_->levelDimensions().x(); int lh = lvl_->levelDimensions().y(); int sx = startPos_.x()-30; if(sx <= 0) sx = 0; int sy = startPos_.y()-30; if(sy <= 0) sy = 0; int ex = startPos_.x()+30; if(ex >= lw) ex = lw; int ey = startPos_.y()+30; if(ey >= lh) ey = lh; if(!(int(pos.x()) >= sx && int(pos.x()) < ex && int(pos.y()) >= sy && int(pos.y()) < ey)) return; if(Util::List::findElement(visited_, pos)) return; std::vector<QVector2D> neighbours; auto leftPos = QVector2D(int(pos.x())-1, int(pos.y())); auto left = lvl_->getTile(leftPos.x(), leftPos.y(), lvl_->currentLayer()); if(left && int(left->setLocation.x()) == int(fillTile_->setLocation.x()) && int(left->setLocation.y()) == int(fillTile_->setLocation.y())) if(!Util::List::findElement(visited_, leftPos)) neighbours.push_back(leftPos); auto topPos = QVector2D(int(pos.x()), int(pos.y())-1); auto top = lvl_->getTile(topPos.x(), topPos.y(), lvl_->currentLayer()); if(top && int(top->setLocation.x()) == int(fillTile_->setLocation.x()) && int(top->setLocation.y()) == int(fillTile_->setLocation.y())) if(!Util::List::findElement(visited_, topPos)) neighbours.push_back(topPos); auto rightPos = QVector2D(int(pos.x())+1, int(pos.y())); auto right = lvl_->getTile(rightPos.x(), rightPos.y(), lvl_->currentLayer()); if(right && int(right->setLocation.x()) == int(fillTile_->setLocation.x()) && int(right->setLocation.y()) == int(fillTile_->setLocation.y())) if(!Util::List::findElement(visited_, rightPos)) neighbours.push_back(rightPos); auto downPos = QVector2D(int(pos.x()), int(pos.y())+1); auto down = lvl_->getTile(downPos.x(), downPos.y(), lvl_->currentLayer()); if(down && int(down->setLocation.x()) == int(fillTile_->setLocation.x()) && int(down->setLocation.y()) == int(fillTile_->setLocation.y())) if(!Util::List::findElement(visited_, downPos)) neighbours.push_back(downPos); std::pair<int,int> pair = std::make_pair(int(pos.x()), int(pos.y())); if(!Util::Map::findKey(urTiles_,pair)) { auto prevTile = lvl_->getTile(pair.first, pair.second, lvl_->currentLayer()); URTile prev; if(prevTile) { prev = {*prevTile, pos, lvl_->currentLayer()}; } else prev = {Tile(), QVector2D(-1,-1), lvl_->currentLayer()}; std::pair<URTile,URTile> urPair = std::pair<URTile,URTile>(prev,{*selectedTile_,pos, lvl_->currentLayer()}); urTiles_[pair] = urPair; } visited_.push_back(pos); for(auto &n : neighbours) neighbourCheck(n); }

QVariant SketchConstraintsSolver::solve() { this->solved = false; if(this->sketch == Q_NULLPTR) { return "Sketch is null"; } /* * get the mm/pixel scale */ QVariant isScaleSet; bool isIsMmPerPixelScaleSetCallWorks = QMetaObject::invokeMethod( this->sketch, "isMmPerPixelScaleSet", Q_RETURN_ARG(QVariant, isScaleSet) ); if(!isIsMmPerPixelScaleSetCallWorks) { return "Cannot check if the scale is set"; } if(!isScaleSet.toBool()) { return "Cannot apply constraints without scale"; } QVariant mmPerPixelScale; bool isGetMmPerPixelScaleCallWorks = QMetaObject::invokeMethod( this->sketch, "getMmPerPixelScale", Q_RETURN_ARG(QVariant, mmPerPixelScale) ); if(!isGetMmPerPixelScaleCallWorks) { return "Cannot retrieve the scale"; } double pixelPerMmScale = 1.0 / mmPerPixelScale.toDouble(); // clean old computation this->points.clear(); this->lines.clear(); this->constraints.clear(); bool first = false; // extract sketch data QVariantMap store = this->sketch->property("store").value<QVariantMap>(); QVariantList points = store["points"].value<QVariantList>(); QVariantList lines = store["lines"].value<QVariantList>(); foreach(QVariant item, points) { QObject* point = item.value<QObject*>(); if(first) { this->origin = point->property("start").value<QVector2D>(); first = false; } QVector2D start = point->property("start").value<QVector2D>(); QSharedPointer<ConstrainedPoint> newPoint(new ConstrainedPoint( start.x() - this->origin.x(), start.y() - this->origin.y(), point )); this->points[newPoint->identifier().toInt()] = newPoint; }

QT_BEGIN_NAMESPACE /*! \class QTriangle3D \brief The QTriangle3D class represents a triangle as three points in 3D space. \since 4.8 \ingroup qt3d \ingroup qt3d::math A triangle is defined by 3 points in 3D space. Since any 3 points define a plane, the triangle can be thought of as defining a plane, and forming a geometric region in that plane. If you need a simple plane, with no particular geometry, then QPlane3D is a more compact and mathematically sufficient class. The three points are labelled p(), q() and r() for consistency with textbook treatments. It is recommended that the points be supplied in counter-clockwise order for correct orientation of the triangle's plane(). \sa QPlane3D */ /*! \fn QTriangle3D::QTriangle3D() Constructs a default triangle which lies in the x-z plane, with the three vertices (0, 0, 0), (1, 0, 0), and (0, 1, 0). */ /*! \fn QTriangle3D::QTriangle3D(const QVector3D &p, const QVector3D &q, const QVector3D &r) Constructs a triangle with the supplied \a p, \a q and \a r vertices. */ /*! \fn QVector3D QTriangle3D::p() const Returns the value of the P vertex on the triangle. \sa q(), r(), setP() */ /*! \fn void QTriangle3D::setP(const QVector3D &point) Sets the value of the P vertex on the triangle to \a point. \sa setQ(), setR(), p() */ /*! \fn QVector3D QTriangle3D::q() const Returns the value of the Q vertex on the triangle. \sa p(), r(), setQ() */ /*! \fn void QTriangle3D::setQ(const QVector3D &point) Sets the value of the Q vertex on the triangle \a point. \sa setP(), setR(), q() */ /*! \fn QVector3D QTriangle3D::r() const Returns the value of the R vertex on the triangle. \sa p(), q(), setR() */ /*! \fn void QTriangle3D::setR(const QVector3D &point) Sets the value of the R vertex on the triangle \a point. \sa setP(), setQ(), r() */ /*! \fn QPlane3D QTriangle3D::plane() const Returns the plane in which the triangle lies. \sa QPlane3D */ /*! \fn QVector3D QTriangle3D::center() const Returns the center of the triangle, which is the geometric average of the three vertices. */ /*! \fn QVector3D QTriangle3D::faceNormal() const Returns the vector normal to this triangle, computed from the cross-product of P-Q and Q-R. The result is not normalized. */ static inline bool uvInTriangle(const QVector2D &c) { if (c.x() < 0.0f || c.x() > 1.0f) return false; if (c.y() < 0.0f || c.y() > 1.0f) return false; if ((c.x() + c.y()) > 1.0f) return false; return true; }

/*! Constructs a 3D vector from the specified 2D \a vector. The z coordinate is set to zero. \sa toVector2D() */ QVector3DD::QVector3DD(const QVector2D& vector) { xp = vector.x(); yp = vector.y(); zp = 0.0f; }

QVector3D SphereProjector::computeSphereIntersectionCoordinates(QVector2D screenVector){ auto x = screenVector.x(); auto y = screenVector.y(); auto z = -std::sqrt(sqr(rScaled) - sqr(x) - sqr(y)); return QVector3D(x, y, z); }

void HydroFileTests::vectorTest() { QVector2D vect = hydroFile_.getVector(1,1); QCOMPARE(1.1f, vect.x()); QCOMPARE(1.2f, vect.y()); vect = hydroFile_.getVector(2,2); QCOMPARE(2.1f, vect.x()); QCOMPARE(2.2f, vect.y()); vect = hydroFile_.getVector(3,3); QCOMPARE(3.1f, vect.x()); QCOMPARE(3.2f, vect.y()); vect = hydroFile_.getVector(4,4); QCOMPARE(4.1f, vect.x()); QCOMPARE(4.2f, vect.y()); vect = hydroFile_.getVector(5,5); QCOMPARE(5.1f, vect.x()); QCOMPARE(5.2f, vect.y()); }

double Distance2D(QVector2D point1, QVector2D point2) { return sqrt( pow((point2.x()-point1.x()),2) + pow((point2.y()-point1.y()),2)); }

/*! * Returns the target orientation. */ double ObstacleAvoidance::targetOrientationRad(PositionMeters targetPosition) { QVector2D totalForce = m_potentialField->computeTotalForceForRobot(targetPosition); return qAtan2(totalForce.y(), totalForce.x()); }

Cone::Cone(const QVector2D &pc, const QVector3D &pos) : Object(AMBIENT, DIFFUSE, SPECULAR, SHININESS,REFLECTION, REFRACTION) { c = pc.normalized(); position = pos; }

/** * Computes the intersection between two line segments on the XY plane. * Segments must intersect within their extents for the intersection to be valid. z coordinate is ignored. * * @param a one end of the first line * @param b another end of the first line * @param c one end of the second line * @param d another end of the second line * @param tab * @param tcd * @param segmentOnly * @param intPoint the intersection * @return true if two lines intersect / false otherwise **/ bool Util::segmentSegmentIntersectXY(const QVector2D& a, const QVector2D& b, const QVector2D& c, const QVector2D& d, float *tab, float *tcd, bool segmentOnly, QVector2D& intPoint) { QVector2D u = b - a; QVector2D v = d - c; if (u.lengthSquared() < MTC_FLOAT_TOL || v.lengthSquared() < MTC_FLOAT_TOL) { return false; } float numer = v.x()*(c.y()-a.y()) + v.y()*(a.x()-c.x()); float denom = u.y()*v.x() - u.x()*v.y(); if (denom == 0.0f) { // they are parallel *tab = 0.0f; *tcd = 0.0f; return false; } float t0 = numer / denom; QVector2D ipt = a + t0*u; QVector2D tmp = ipt - c; float t1; if (QVector2D::dotProduct(tmp, v) > 0.0f){ t1 = tmp.length() / v.length(); } else { t1 = -1.0f * tmp.length() / v.length(); } //Check if intersection is within segments if(segmentOnly && !( (t0 >= MTC_FLOAT_TOL) && (t0 <= 1.0f-MTC_FLOAT_TOL) && (t1 >= MTC_FLOAT_TOL) && (t1 <= 1.0f-MTC_FLOAT_TOL) ) ){ return false; } *tab = t0; *tcd = t1; QVector2D dirVec = b-a; intPoint = a+(*tab)*dirVec; return true; }

QVector2D Graph::graphToNode(QVector2D graph) { QVector2D ret; ret.setX(graphToNodeX(graph.x())); ret.setY(graphToNodeY(graph.y())); return ret; }

void CALLBACK tessVertexCB(const GLvoid *data, void *user_data) { GLdouble* vertData = (GLdouble*)data; QVector2D vert; vert.setX(vertData[0]); vert.setY(vertData[1]); B9Tesselator* tess = (B9Tesselator*)user_data; if(tess->currentEnumType == GL_TRIANGLES) { tess->GetTrangleStrip()->push_back(vert); } else if(tess->currentEnumType == GL_TRIANGLE_FAN) { if(tess->fanFirstTri) { tess->fanOriginVertex = vert; tess->fanFirstTri = false; tess->fanSecondTri = true; return; } else if(tess->fanSecondTri) { tess->fanFirstTri = false; tess->fanSecondTri = false; tess->prevVertex = vert; } else { tess->GetTrangleStrip()->push_back(tess->fanOriginVertex); tess->GetTrangleStrip()->push_back(tess->prevVertex); tess->GetTrangleStrip()->push_back(vert); tess->prevVertex = vert; } } else if(tess->currentEnumType == GL_TRIANGLE_STRIP) { if(tess->stripFirstTri) { tess->prevPrevVertex = vert; tess->stripFirstTri = false; tess->stripSecondTri = true; return; } else if(tess->stripSecondTri) { tess->prevVertex = vert; tess->stripFirstTri = false; tess->stripSecondTri = false; } else { if(tess->stripCount%2)//odd { tess->GetTrangleStrip()->push_back(tess->prevVertex); tess->GetTrangleStrip()->push_back(tess->prevPrevVertex); tess->GetTrangleStrip()->push_back(vert); } else { tess->GetTrangleStrip()->push_back(tess->prevPrevVertex); tess->GetTrangleStrip()->push_back(tess->prevVertex); tess->GetTrangleStrip()->push_back(vert); } tess->prevPrevVertex = tess->prevVertex; tess->prevVertex = vert; } tess->stripCount++; } else { qDebug() << "B9Tesselator: WARNING! un-implemented OpenGl Triangle Enum!"; } }

/** * 近くに頂点またはエッジがあるなら、コネクトしちゃう。 * コネクトできた場合は、trueを返却する。 * コネクトできなかった場合は、falseを返却する。 */ bool PatchRoadGenerator::attemptConnect(int roadType, RoadVertexDesc srcDesc, int ex_id, std::vector<ExFeature>& features, std::list<RoadVertexDesc> &seeds) { float length = 0.0f; if (roadType == RoadEdge::TYPE_AVENUE) { length = features[ex_id].avgAvenueLength; } else { length = features[ex_id].avgStreetLength; } // スナップする際、許容できる角度 // attemptConnectでは、許容できる角度を厳しくしてみる。 float roadAngleTolerance = G::getFloat("roadAngleTolerance") * 2.0f; std::vector<RoadEdgePtr> edges; // 当該頂点から出るエッジをリストアップし、基底の方向を決定する float direction = 0.0f; { RoadOutEdgeIter ei, eend; for (boost::tie(ei, eend) = boost::out_edges(srcDesc, roads.graph); ei != eend; ++ei) { if (!roads.graph[*ei]->valid) continue; Polyline2D polyline = GraphUtil::orderPolyLine(roads, *ei, srcDesc); QVector2D vec = polyline[1] - polyline[0]; direction = atan2f(vec.y(), vec.x()); break; } } // 既にあるエッジと正反対の方向を計算 direction += 3.141592653; // ものすごい近くに、他の頂点がないかあれば、そことコネクトして終わり。 // それ以外の余計なエッジは生成しない。さもないと、ものすごい密度の濃い道路網になっちゃう。 { RoadVertexDesc nearestDesc; if (GraphUtil::getVertexExceptDeadend(roads, srcDesc, length, direction, 0.3f, nearestDesc)) { // もし、既にエッジがあるなら、キャンセル // なお、ここではtrueを返却して、これ以上のエッジ生成をさせない。 if (GraphUtil::hasEdge(roads, srcDesc, nearestDesc)) return true; // その頂点のexample_descと、この頂点のexample_descの位置関係と、実際の位置関係が同じ場合、 // patch適用でピッタリはまるはずなので、connectしない。 { RoadVertexDesc ex_v1_desc; RoadVertexDesc ex_v2_desc; int pre_ex_id = roads.graph[srcDesc]->properties["ex_id"].toInt(); bool has_ex_v1 = false; bool has_ex_v2 = false; if (roadType == RoadEdge::TYPE_AVENUE) { if (roads.graph[srcDesc]->properties.contains("example_desc")) { has_ex_v1 = true; ex_v1_desc = roads.graph[srcDesc]->properties["example_desc"].toUInt(); } if (roads.graph[nearestDesc]->properties["ex_id"].toInt() == pre_ex_id) { if (roads.graph[nearestDesc]->properties.contains("example_desc")) { has_ex_v2 = true; ex_v2_desc = roads.graph[nearestDesc]->properties["example_desc"].toUInt(); } } } else { if (roads.graph[srcDesc]->properties.contains("example_street_desc")) { has_ex_v1 = true; ex_v1_desc = roads.graph[srcDesc]->properties["example_street_desc"].toUInt(); } if (roads.graph[nearestDesc]->properties["ex_id"].toInt() == pre_ex_id) { if (roads.graph[nearestDesc]->properties.contains("example_street_desc")) { has_ex_v2 = true; ex_v2_desc = roads.graph[nearestDesc]->properties["example_street_desc"].toUInt(); } } } if (has_ex_v1 && has_ex_v2) { QVector2D ex_vec = features[pre_ex_id].roads(roadType).graph[ex_v2_desc]->pt - features[pre_ex_id].roads(roadType).graph[ex_v1_desc]->pt; QVector2D vec = roads.graph[nearestDesc]->pt - roads.graph[srcDesc]->pt; if ((vec - ex_vec).lengthSquared() <= 0.1f) return false; } } RoadEdgePtr e = RoadEdgePtr(new RoadEdge(roadType, 1)); e->polyline.push_back(roads.graph[srcDesc]->pt); e->polyline.push_back(roads.graph[nearestDesc]->pt); // スナップ先にとってredundantなら、コネクトしないで、終了。 // つまり、trueを返却して、終わったことにしちゃう。 /* if (roadType == RoadEdge::TYPE_AVENUE) { Polyline2D e2; e2.push_back(QVector2D(0, 0)); e2.push_back(roads.graph[srcDesc]->pt - roads.graph[nearestDesc]->pt); if (RoadGeneratorHelper::isRedundantEdge(roads, nearestDesc, e2, roadAngleTolerance)) { // もしdegree=1なら、連なるエッジをごっそり削除 if (roadType == RoadEdge::TYPE_AVENUE && GraphUtil::getDegree(roads, srcDesc) == 1) { RoadOutEdgeIter ei, eend; for (boost::tie(ei, eend) = boost::out_edges(srcDesc, roads.graph); ei != eend; ++ei) { removeEdge(roads, srcDesc, *ei); } } return true; } } */ if (!GraphUtil::isIntersect(roads, e->polyline)) { RoadEdgeDesc e_desc = GraphUtil::addEdge(roads, srcDesc, nearestDesc, e); return true; } } } // 近くにエッジがあれば、コネクト { RoadVertexDesc nearestDesc; RoadEdgeDesc nearestEdgeDesc; QVector2D intPoint; if (GraphUtil::getCloseEdge(roads, srcDesc, length, direction, 0.3f, nearestEdgeDesc, intPoint)) { // エッジにスナップ nearestDesc = GraphUtil::splitEdge(roads, nearestEdgeDesc, intPoint); roads.graph[nearestDesc]->properties["generation_type"] = "snapped"; roads.graph[nearestDesc]->properties["group_id"] = roads.graph[nearestEdgeDesc]->properties["group_id"]; roads.graph[nearestDesc]->properties["ex_id"] = roads.graph[nearestEdgeDesc]->properties["ex_id"]; roads.graph[nearestDesc]->properties.remove("example_desc"); RoadEdgePtr e = RoadEdgePtr(new RoadEdge(roadType, 1)); e->polyline.push_back(roads.graph[srcDesc]->pt); e->polyline.push_back(roads.graph[nearestDesc]->pt); RoadEdgeDesc e_desc = GraphUtil::addEdge(roads, srcDesc, nearestDesc, e); return true; } } // ものすごい近くに、他の頂点がないかあれば、そことコネクトして終わり。 // それ以外の余計なエッジは生成しない。さもないと、ものすごい密度の濃い道路網になっちゃう。 { RoadVertexDesc nearestDesc; if (GraphUtil::getVertexExceptDeadend(roads, srcDesc, length, direction, 1.5f, nearestDesc)) { // もし、既にエッジがあるなら、キャンセル // なお、ここではtrueを返却して、これ以上のエッジ生成をさせない。 if (GraphUtil::hasEdge(roads, srcDesc, nearestDesc)) return true; // その頂点のexample_descと、この頂点のexample_descの位置関係と、実際の位置関係が同じ場合、 // patch適用でピッタリはまるはずなので、connectしない。 { RoadVertexDesc ex_v1_desc; RoadVertexDesc ex_v2_desc; int pre_ex_id = roads.graph[srcDesc]->properties["ex_id"].toInt(); bool has_ex_v1 = false; bool has_ex_v2 = false; if (roadType == RoadEdge::TYPE_AVENUE) { if (roads.graph[srcDesc]->properties.contains("example_desc")) { has_ex_v1 = true; ex_v1_desc = roads.graph[srcDesc]->properties["example_desc"].toUInt(); } if (roads.graph[nearestDesc]->properties["ex_id"].toInt() == pre_ex_id) { if (roads.graph[nearestDesc]->properties.contains("example_desc")) { has_ex_v2 = true; ex_v2_desc = roads.graph[nearestDesc]->properties["example_desc"].toUInt(); } } } else { if (roads.graph[srcDesc]->properties.contains("example_street_desc")) { has_ex_v1 = true; ex_v1_desc = roads.graph[srcDesc]->properties["example_street_desc"].toUInt(); } if (roads.graph[nearestDesc]->properties["ex_id"].toInt() == pre_ex_id) { if (roads.graph[nearestDesc]->properties.contains("example_street_desc")) { has_ex_v2 = true; ex_v2_desc = roads.graph[nearestDesc]->properties["example_street_desc"].toUInt(); } } } if (has_ex_v1 && has_ex_v2) { QVector2D ex_vec = features[pre_ex_id].roads(roadType).graph[ex_v2_desc]->pt - features[pre_ex_id].roads(roadType).graph[ex_v1_desc]->pt; QVector2D vec = roads.graph[nearestDesc]->pt - roads.graph[srcDesc]->pt; if ((vec - ex_vec).lengthSquared() <= 0.1f) return false; } } RoadEdgePtr e = RoadEdgePtr(new RoadEdge(roadType, 1)); e->polyline.push_back(roads.graph[srcDesc]->pt); e->polyline.push_back(roads.graph[nearestDesc]->pt); // スナップ先にとってredundantなら、コネクトしないで、終了。 // つまり、trueを返却して、終わったことにしちゃう。 /* if (roadType == RoadEdge::TYPE_AVENUE) { Polyline2D e2; e2.push_back(QVector2D(0, 0)); e2.push_back(roads.graph[srcDesc]->pt - roads.graph[nearestDesc]->pt); if (RoadGeneratorHelper::isRedundantEdge(roads, nearestDesc, e2, roadAngleTolerance)) { // もしdegree=1なら、連なるエッジをごっそり削除 if (roadType == RoadEdge::TYPE_AVENUE && GraphUtil::getDegree(roads, srcDesc) == 1) { RoadOutEdgeIter ei, eend; for (boost::tie(ei, eend) = boost::out_edges(srcDesc, roads.graph); ei != eend; ++ei) { removeEdge(roads, srcDesc, *ei); } } return true; } } */ if (!GraphUtil::isIntersect(roads, e->polyline)) { RoadEdgeDesc e_desc = GraphUtil::addEdge(roads, srcDesc, nearestDesc, e); return true; } } } return false; }