/* * This file is part of libfmr * * File: Region.cpp * Author: Florian Heinz * * Created on September 9, 2016, 3:20 PM //paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}] //[TOC] [\tableofcontents] [1] Implementation of the class ~Region~ [TOC] 1 Overview The class ~Region~ represents a set of faces. A face is a polygon with optionally one or more holes (see also Face.cpp) */ #include "fmr_Region.h" #include "fmr_FMRegion.h" #include using namespace fmr; /* 2 Constructor Create a Region from an RList representation. */ Region::Region(RList& l) { for (int i = 0; i < l.size(); i++) { Face f(l[i]); faces.push_back(f); } } /* 3 ~inside~ Tests, if a point is inside a region. A point is exactly then inside a region, if it is inside a face of this region. */ bool Region::inside(Point p) { for (int i = 0; i < faces.size(); i++) { if (faces[i].inside(p)) return true; } return false; } /* 4 ~transform~ Transform a region according to the given TransformationUnit ~tu~ at the fraction ~frac~ of the interval. */ Region Region::transform(TransformationUnit& tu, double frac) { Region r; for (int i = 0; i < faces.size(); i++) { // Transform each face r.faces.push_back(faces[i].transform(tu, frac)); } return r; } /* 5 ~getAllSegments~ Returns all segments of this region (including all faces and holes) */ std::vector Region::getAllSegments() { std::vector ret; for (int nrface = 0; nrface < faces.size(); nrface++) { Face& face = faces[nrface]; ret.insert(ret.end(), face.segs.begin(), face.segs.end()); for (int nrhole = 0; nrhole < face.holes.size(); nrhole++) { Face& hole = face.holes[nrhole]; ret.insert(ret.end(), hole.segs.begin(), hole.segs.end()); } } return ret; } /* 6 ~checkTransformation~ Check, if the transformation ~tu~ transforms all segments ~segs1~ to the segments in ~segs2~. Used to find a valid interpolation. */ static bool checkTransformation(TransformationUnit& tu, std::vector segs1, std::vector segs2) { for (int s1 = 0; s1 < segs1.size(); s1++) { Seg& seg1 = segs1[s1]; std::vector::iterator s2it = segs2.begin(); bool found = false; while (s2it != segs2.end()) { Seg& seg2 = *s2it; if (seg1.transform(tu, 1).near(seg2, 0.01)) { found = true; segs2.erase(s2it); break; } s2it++; } if (!found) return false; } return true; } /* 7 ~interpolate~ Find a valid interpolation of this region with the specified region ~r~ over the interval ~iv~. The desired center point of the rotation is the centroid of the region. */ FMRegion Region::interpolate(Region& r, Interval iv) { return interpolate(r, this->centroid(), iv); } /* 8 ~interpolate~ Find a valid interpolation of this region with the specified region ~r~ over the interval ~iv~ using the centerpoint ~center~. The success of the operation is not depending on the choice of the center point. */ FMRegion Region::interpolate(Region& r, Point center, Interval iv) { std::vector segs1 = getAllSegments(); std::vector segs2 = r.getAllSegments(); std::pair trafo; if (segs1.size() == 0 || segs1.size() != segs2.size()) { return FMRegion(); } // Choose the longest segment of segs1 (to minimize numeric instabilities) Seg seg1 = segs1[0]; for (int s1 = 1; s1 < segs1.size(); s1++) { Seg tmp = segs1[s1]; if (tmp.length() > seg1.length()) seg1 = tmp; } // And for each segment in segs2 ... for (int s2 = 0; s2 < segs2.size(); s2++) { Seg& seg2 = segs2[s2]; // ... try to find a valid transformation to convert seg1 to seg2 trafo = seg1.calculateTransformation(seg2, center, 0.01); if (!trafo.first) continue; // If such a transformation was found, check if it is valid for // all other segments, too. If this is the case, we have found // a valid interpolation. if (checkTransformation(trafo.second, segs1, segs2)) break; else trafo.first = false; } if (trafo.first) { // A valid interpolation was found, create an FMRegion from it trafo.second.iv = iv; return FMRegion(*this, trafo.second); } else { // No valid interpolation was found, return an empty FMRegion return FMRegion(); } } /* 9 ~area~ Calculates the area of this region as the sum of the area of all faces. */ double Region::area() { double ret = 0; for (int nrface = 0; nrface < faces.size(); nrface++) { ret += faces[nrface].area(); } return ret; } /* 10 ~centroid~ Calculates the centroid of this region from the faces and the area. */ Point Region::centroid() { double A = area(); double xs = 0, ys = 0; for (int nrface = 0; nrface < faces.size(); nrface++) { std::pair p = faces[nrface].centroidParams(); xs += p.first; ys += p.second; } return Point(xs/(A*6.0), ys/(A*6.0)); } /* 11 ~BoundingBox~ Return the bounding box of this region. */ BoundingBox Region::boundingBox() { BoundingBox bb; for (unsigned int nrface = 0; nrface < faces.size(); nrface++) { Face& f = faces[nrface]; bb.update(f.boundingBox()); } return bb; } /* 12 ~ToString~ Return a string representation of this region. */ std::string Region::ToString() { std::string ret = ""; for (int i = 0; i < faces.size(); i++) { ret += "( " + faces[i].ToString() + " )\n"; } return ret; } /* 13 ~toRList~ Return an RList representation of this region. */ RList Region::toRList() { RList ret; for (int nrface = 0; nrface < faces.size(); nrface++) { ret.append(faces[nrface].toRList()); } return ret; }