Files
2026-01-23 17:03:45 +08:00

188 lines
4.4 KiB
C++

/*
* This file is part of libfmr
*
* File: RFace.cpp
* Author: Florian Heinz <fh@sysv.de>
*
* Created on September 20, 2016, 10:48 PM
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
//[TOC] [\tableofcontents]
[1] Implementation of the class ~Point~
[TOC]
1 Overview
The class ~RFace~ represents a face of a CRegion. It is constructed from
~RCurve~-Segments (see RCurve.cpp) and can contain one or more holes,
which are also RFaces.
*/
#include "fmr_RFace.h"
#include "fmr_RCurve.h"
using namespace fmr;
/*
2 Construct from RList
Constructs an RFace from its RList representation.
*/
RFace::RFace(RList &r) {
getCycle(r[0]); // Get the main cycle
for (int i = 1; i < r.size(); i++) {
RFace hole; // Get (optional) hole cycles
hole.getCycle(r[i]);
holes.push_back(hole);
}
}
/*
3 ~getCycle~
Read a single cycle from an ~RList~.
*/
void RFace::getCycle(RList& r) {
for (int i = 0; i < r.size(); i++) {
face.push_back(RCurve(r[i]));
}
}
/*
4 ~intersections~
Calculate all intersections of line segment ~s~ with this ~RFace~.
This includes intersections with holes.
*/
std::vector<Point> RFace::intersections(Seg s) {
std::vector<Point> ret;
for (int nrcycle = -1; nrcycle < (int) holes.size(); nrcycle++) {
RFace& rf = (nrcycle < 0) ? * this : holes[nrcycle];
for (int nrrcurve = 0; nrrcurve < rf.face.size(); nrrcurve++) {
RCurve& rc = rf.face[nrrcurve];
std::vector<Point> is = rc.intersections(s);
ret.insert(ret.end(), is.begin(), is.end());
}
}
return ret;
}
/*
5 ~inside~
Test, if a given Point ~p~ is inside this RFace.
Uses the plumbline algorithm: Count the number of intersections between the
Point ~p~ and a point guaranteed to be outside the face. If the number is odd,
the point is inside. This also works if the point is inside a hole of this face.
*/
bool RFace::inside(Point p) {
// A point outside the bounding box is guaranteed to be outside the RFace
Point outside = boundingBox().lowerLeft - Point(100, 100);
std::vector<Point> is = intersections(Seg(p, outside));
return is.size()&1;
}
/*
6 ~intersects~
Test, if a given Face ~f~ intersects or overlaps with this RFace.
*/
bool RFace::intersects(Face& f) {
// Test each segment of the Face f for intersection with the main cycle or
// a hole cycle. Both means, the Faces intersect.
for (unsigned int nrseg = 0; nrseg < f.segs.size(); nrseg++) {
std::vector<Point> is = intersections(f.segs[nrseg]);
if (is.size() > 0)
return true; // We have an intersection
}
// Is the Face f completely inside this RFace?
Point p = f.segs[0].i;
if (inside(p))
return true; // Yes, since a point of the face is inside the RFace and
// there are no intersections
// Is the RFace completely inside the Face f?
Point p2 = face[0].off;
if (f.inside(p2))
return true; // Yes, since a point of the RFace is inside the Face and
// there are no intersections.
return false;
}
/*
7 boundingBox
Calculate the bounding box for this RFace. This is not necessarily a minimal
bounding box.
*/
BoundingBox RFace::boundingBox() {
BoundingBox bb;
for (unsigned int nrseg = 0; nrseg < face.size(); nrseg++) {
RCurve& rc = face[nrseg];
bb.update(rc.boundingBox());
}
return bb;
}
/*
8 ~toFace~
Converts this RFace to a standard Region Face by approximating the border with
~nrsegs~ straight segments. Also converts its holes.
*/
Face RFace::toFace(int nrsegs) {
Face ret;
int facesegs = face.size();
for (int i = 0; i < facesegs; i++) {
std::vector<Seg> segs = face[i].toSegs(nrsegs/facesegs+1);
ret.segs.insert(ret.segs.end(), segs.begin(), segs.end());
}
// Now convert the holes
for (int nrhole = 0; nrhole < holes.size(); nrhole++) {
ret.holes.push_back(holes[nrhole].toFace(nrsegs));
}
return ret;
}
/*
9 ~toRList~
Returns an RList representation of this RFace.
*/
RList RFace::toRList() {
RList ret;
RList& mf = ret.nest();
for (int i = 0; i < face.size(); i++) {
mf.append(face[i].toRList());
}
for (int j = 0; j < holes.size(); j++) {
RFace& hole = holes[j];
RList& hl = ret.nest();
for (int i = 0; i < hole.face.size(); i++) {
hl.append(hole.face[i].toRList());
}
}
return ret;
}