void PMRoadGenerator::setupTensor(const Polygon2D& targetArea, const std::vector<std::pair<QVector2D, float>>& regular_elements, cv::Mat& tensor) {
	BBox bbox = targetArea.envelope();
	tensor = cv::Mat(bbox.dy() + 1, bbox.dx() + 1, CV_32F);

	for (int r = 0; r < tensor.rows; ++r) {
		for (int c = 0; c < tensor.cols; ++c) {
			int x = c + bbox.minPt.x();
			int y = r + bbox.minPt.y();

			double total_angle = 0.0;
			double total_weight = 0.0;
			for (int k = 0; k < regular_elements.size(); ++k) {
				float dist = (QVector2D(x, y) - regular_elements[k].first).length();

				double angle = regular_elements[k].second;
				double weight = exp(-dist / 10);
				total_angle += angle * weight;
				total_weight += weight;
			}

			float avg_angle = total_angle / total_weight;
			tensor.at<float>(r, c) = avg_angle;
		}
	}
}
void VBOPmBlocks::saveBlockImage(RoadGraph& roads, Polygon3D& contour, const char* filename) {
	BBox bbox = GraphUtil::getAABoundingBox(roads, true);
	cv::Mat img(bbox.dy() + 1, bbox.dx() + 1, CV_8UC3, cv::Scalar(255, 255, 255));

	RoadEdgeIter ei, eend;
	for (boost::tie(ei, eend) = boost::edges(roads.graph); ei != eend; ++ei) {
		if (!roads.graph[*ei]->valid) continue;

		for (int pl = 0; pl < roads.graph[*ei]->polyline.size() - 1; ++pl) {
			int x1 = roads.graph[*ei]->polyline[pl].x() - bbox.minPt.x();
			int y1 = img.rows - (roads.graph[*ei]->polyline[pl].y() - bbox.minPt.y());
			int x2 = roads.graph[*ei]->polyline[pl + 1].x() - bbox.minPt.x();
			int y2 = img.rows - (roads.graph[*ei]->polyline[pl + 1].y() - bbox.minPt.y());
			cv::line(img, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(224, 224, 224), 3);
		}
	}

	for (int i = 0; i < contour.contour.size(); ++i) {
		int next = (i + 1) % contour.contour.size();
		int x1 = contour.contour[i].x() - bbox.minPt.x();
		int y1 = img.rows - (contour.contour[i].y() - bbox.minPt.y());
		int x2 = contour.contour[next].x() - bbox.minPt.x();
		int y2 = img.rows - (contour.contour[next].y() - bbox.minPt.y());
		cv::line(img, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 0, 0), 3);
	}

	cv::imwrite(filename, img);
}
void PMRoadGenerator::saveRoadImage(RoadGraph& roads, const std::string& filename) {
	BBox bbox;
	RoadVertexIter vi, vend;
	for (boost::tie(vi, vend) = boost::vertices(roads.graph); vi != vend; ++vi) {
		if (!roads.graph[*vi]->valid) continue;

		bbox.addPoint(roads.graph[*vi]->pt);
	}

	cv::Mat result((int)(bbox.dy() + 1), (int)(bbox.dx() + 1), CV_8UC3, cv::Scalar(255, 255, 255));

	RoadEdgeIter ei, eend;
	for (boost::tie(ei, eend) = boost::edges(roads.graph); ei != eend; ++ei) {
		if (!roads.graph[*ei]->valid) continue;

		for (int k = 0; k < roads.graph[*ei]->polyline.size() - 1; ++k) {
			int x1 = roads.graph[*ei]->polyline[k].x() - bbox.minPt.x();
			int y1 = roads.graph[*ei]->polyline[k].y() - bbox.minPt.y();
			int x2 = roads.graph[*ei]->polyline[k + 1].x() - bbox.minPt.x();
			int y2 = roads.graph[*ei]->polyline[k + 1].y() - bbox.minPt.y();

			cv::line(result, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 0, 0), 1, cv::LINE_AA);
		}
	}

	for (boost::tie(vi, vend) = boost::vertices(roads.graph); vi != vend; ++vi) {
		if (!roads.graph[*vi]->valid) continue;

		int count = 0;
		RoadOutEdgeIter oi, oend;
		for (boost::tie(oi, oend) = boost::out_edges(*vi, roads.graph); oi != oend; ++oi) {
			if (roads.graph[*oi]->valid) count++;
		}

		if (count == 2) continue;

		int x = roads.graph[*vi]->pt.x() - bbox.minPt.x();
		int y = roads.graph[*vi]->pt.y() - bbox.minPt.x();
		cv::circle(result, cv::Point(x, y), 5, cv::Scalar(255, 0, 0), 1, cv::LINE_AA);

		QString text = QString::number(count);
		cv::putText(result, text.toUtf8().constData(), cv::Point(x, y), cv::FONT_HERSHEY_PLAIN, 2, cv::Scalar(0, 0, 0), 1, cv::LINE_AA);
	}

	cv::imwrite(filename.c_str(), result);
}
/**
 * KDEベースでの特徴量を抽出する。
 */
void KDEFeatureExtractor::extractFeature(RoadGraph& roads, Polygon2D& area, RoadFeature& roadFeature) {
	roadFeature.clear();

	KDEFeaturePtr kf = KDEFeaturePtr(new KDEFeature(0));

	QVector2D center = area.envelope().midPt();

	///////////////////////////////////////////////////////////////////////////////////////////////////////
	// Avenueのみを抽出する
	RoadGraph temp_roads;
	time_t start = clock();
	GraphUtil::copyRoads(roads, temp_roads);
	time_t end = clock();
	std::cout << "Elapsed time for copying the roads: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;
	if (G::getBool("exactCut")) {
		GraphUtil::extractRoads2(temp_roads, area);
	}
	start = clock();
	GraphUtil::extractRoads(temp_roads, RoadEdge::TYPE_AVENUE | RoadEdge::TYPE_BOULEVARD);
	end = clock();
	std::cout << "Elapsed time for extracting only the avenues: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;
	start = clock();
	GraphUtil::clean(temp_roads);
	end = clock();
	std::cout << "Elapsed time for cleaning the avenues: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;
	start = clock();
	//GraphUtil::reduce(temp_roads);
	end = clock();
	std::cout << "Elapsed time for reducing the avenues: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;

	// roundaboutを削除する
	//GraphUtil::removeRoundabout(temp_roads);

	// linkを削除する
	start = clock();
	GraphUtil::removeLinkEdges(temp_roads);
	end = clock();
	std::cout << "Elapsed time for removing links: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;
	start = clock();
	//GraphUtil::reduce(temp_roads);
	end = clock();
	std::cout << "Elapsed time for reducing links: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;
	GraphUtil::removeIsolatedVertices(temp_roads);
	start = clock();
	GraphUtil::clean(temp_roads);
	end = clock();
	std::cout << "Elapsed time for cleaning the avenues: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;

	// 特徴量を抽出
	int num_vertices = extractAvenueFeature(temp_roads, area, kf);
	if (G::getBool("perturbation")) {
		extractAvenueFeature(temp_roads, area, kf, true);
	}

	BBox bbox = area.envelope();
	std::cout << "Area: " << area.area() << std::endl;
	std::cout << "BBox: " << bbox.dx() << "," << bbox.dy() << std::endl;
	std::cout << "Num avenue vertices: " << num_vertices << std::endl;

	kf->setDensity(RoadEdge::TYPE_AVENUE, num_vertices / area.area());

	///////////////////////////////////////////////////////////////////////////////////////////////////////
	// streetのみを抽出する
	start = clock();
	GraphUtil::copyRoads(roads, temp_roads);
	end = clock();
	std::cout << "Elapsed time for copying the roads: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;
	if (G::getBool("exactCut")) {
		GraphUtil::extractRoads2(temp_roads, area);
	}
	start = clock();
	GraphUtil::extractRoads(temp_roads, RoadEdge::TYPE_STREET);
	end = clock();
	std::cout << "Elapsed time for extracting the streets: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;
	//GraphUtil::reduce(temp_roads);  <- わざとreduceしない

	// linkを削除する
	start = clock();
	GraphUtil::removeLinkEdges(temp_roads);
	end = clock();
	std::cout << "Elapsed time for removing links: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;
	GraphUtil::removeIsolatedVertices(temp_roads);
	start = clock();
	GraphUtil::clean(temp_roads);
	end = clock();
	std::cout << "Elapsed time for cleaning the streets: " << (double)(end-start)/CLOCKS_PER_SEC << " [sec]" << std::endl;

	// 特徴量を抽出
	num_vertices = extractStreetFeature(temp_roads, area, kf);
	if (G::getBool("perturbation")) {
		extractStreetFeature(temp_roads, area, kf, true);
	}

	kf->setDensity(RoadEdge::TYPE_STREET, num_vertices / area.area());

	kf->setWeight(1.0f);
	kf->setCenter(center);

	// 領域を少しだけ大きくする。これにより、抽出された道路網の交差点が、確実に領域内と判定されるはず。
	for (int i = 0; i < area.size(); ++i) {
		area[i] = (area[i] - center) * 1.02f + center;
	}
	kf->setArea(area);

	roadFeature.addFeature(kf);
}