Skip to content

Commit

Permalink
Gloom: Further fixes for map import and polygon processing
Browse files Browse the repository at this point in the history
  • Loading branch information
skyjake committed Sep 1, 2019
1 parent 9aedb45 commit e88cd42
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 53 deletions.
9 changes: 6 additions & 3 deletions doomsday/apps/gloom/gloom/geo/geomath.h
Expand Up @@ -167,15 +167,18 @@ struct Line
const T d1 = dir();
const T n = normal();
const T d2 = other.dir();
double deg = 180 + radianToDegree(std::acos(clamp(-1.0, d1.dot(d2), 1.0)));
if (n.dot(d2) > 0) deg = 360 - deg;
return deg;
return 180.0 - radianToDegree(std::atan2(n.dot(d2), d1.dot(d2)));
}

T nearestPoint(const T &p) const
{
return start + dir() * dir().dot(p - start);
}

String asText() const
{
return "Line " + start.asText() + " -> " + end.asText();
}
};

using Line2d = Line<Vec2d>;
Expand Down
87 changes: 58 additions & 29 deletions doomsday/apps/gloom/gloom/geo/polygon.cpp
Expand Up @@ -184,12 +184,12 @@ bool Polygon::isLineInside(int start, int end) const
// Both endpoints must be inside.
if (!isPointInside(check.start))
{
qDebug("start %i outside", start);
qDebug("start %i (%x) outside", start, points[start].id);
return false;
}
if (!isPointInside(check.end))
{
qDebug("end %i outside", end);
qDebug("end %i (%x) outside", end, points[end].id);
return false;
}

Expand Down Expand Up @@ -320,6 +320,11 @@ int Polygon::intersect(const Line &check) const

bool Polygon::split(int a, int b, Polygon halves[2]) const
{
for (int i = 0; i < 2; ++i)
{
halves[i].clear();
}

int half = 0;
for (int i = 0; i < size(); ++i)
{
Expand All @@ -334,11 +339,19 @@ bool Polygon::split(int a, int b, Polygon halves[2]) const
for (int i = 0; i < 2; ++i)
{
halves[i].updateBounds();
if (!halves[i].isClockwiseWinding()) return false;
if (!halves[i].isClockwiseWinding())
{
qDebug("\thalf %i has the wrong winding", i);
return false;
}
// Each half must at least be a triangle.
if (halves[i].hasDegenerateEdges())
{
qDebug("\thalf %i has degenerate edges", i);
return false;
}
}

// Each half must at least be a triangle.
return !halves[0].hasDegenerateEdges() && !halves[1].hasDegenerateEdges();
return true;
}

static bool areAllConvex(const QList<Polygon> &polygon)
Expand All @@ -350,12 +363,12 @@ static bool areAllConvex(const QList<Polygon> &polygon)
return true;
}

Rangei Polygon::findLoop() const
Rangei Polygon::findLoop(int findStartPos) const
{
// Having a loop means there's at least two triangles.
if (points.size() < 6) return Rangei();

for (int i = 0; i < points.size(); ++i)
for (int i = findStartPos; i < points.size(); ++i)
{
const ID startPoint = points[i].id;

Expand Down Expand Up @@ -386,6 +399,7 @@ bool Polygon::hasDegenerateEdges() const
if (points[p].id == pointAt(p + 2).id)
{
// This edge forms a zero-area line.
qDebug("\tpoint %i +2 is an empty area", points[p].id);
return true;
}

Expand All @@ -398,6 +412,12 @@ bool Polygon::hasDegenerateEdges() const
{
// Not acceptable; the point falls too close to another line
// on the polygon.
qDebug("\tpoint %i (%x) is on the edge line %i (%x...%x)",
p,
points[p].id,
j,
points[j].id,
pointAt(j + 1).id);
return true;
}
}
Expand All @@ -417,7 +437,7 @@ bool Polygon::isClockwiseWinding() const
angles += lineAt(i).angle(lineAt(i + 1)) - 180.0;
}

// qDebug() << "Winding is" << angles << "for" << asText().toLatin1().constData();
qDebug() << "\tWinding is" << angles << "for" << asText().toLatin1().constData();

return angles < -180; // should be around -360
}
Expand Down Expand Up @@ -466,7 +486,8 @@ QList<Polygon> Polygon::splitConvexParts() const
for (int i = 0; i < parts.size(); ++i)
{
// Loops should be always split to separate polygons.
while (Rangei loop = parts[i].findLoop())
int findBegin = 0;
while (Rangei loop = parts[i].findLoop(findBegin))
{
qDebug() << "Found a loop in" << parts[i].asText() << "indices:" << loop.asText();
Polygon halves[2];
Expand All @@ -476,9 +497,13 @@ QList<Polygon> Polygon::splitConvexParts() const
qDebug() << " " << halves[1].asText();
parts.removeAt(i);
parts.insert(i, halves[0]);
parts.insert(i, halves[1]);
parts.insert(i, halves[1]); // part with the loop removed ends up at `i` again
findBegin = 0;
}
else
{
findBegin = loop.end;
}
else break;
}

Polygon &poly = parts[i];
Expand Down Expand Up @@ -510,25 +535,28 @@ QList<Polygon> Polygon::splitConvexParts() const
if (!poly.isEdgeLine(j, k) && poly.isLineInside(j, k))
{
Polygon halves[2];
if (poly.split(j, k, halves))

int splitStart = j;
int splitEnd = k;

bool ok = poly.split(splitStart, splitEnd, halves);
if (!ok)
{
std::swap(splitStart, splitEnd);
ok = poly.split(splitStart, splitEnd, halves);
}

if (ok)
{
qDebug(" possible split with line %x...%x : %i/%i (cvx:%i/%i, edge:%s, inside:%s)",
poly.pointAt(j).id,
poly.pointAt(k).id,
poly.pointAt(splitStart).id,
poly.pointAt(splitEnd).id,
halves[0].size(),
halves[1].size(),
int(halves[0].isConvex()),
int(halves[1].isConvex()),
poly.isEdgeLine(j, k)?"true":"false",
poly.isLineInside(j, k)?"true":"false");

// parts.removeAt(i);
// parts.append(halves[0]);
// parts.append(halves[1]);
// qDebug() << " Half 1:" << halves[0].asText();
// qDebug() << " Half 2:" << halves[1].asText();
// --i;
// wasSplit = true;
poly.isEdgeLine(splitStart, splitEnd)?"true":"false",
poly.isLineInside(splitStart, splitEnd)?"true":"false");

int score = de::min(halves[0].size(), halves[1].size());
if (halves[0].isConvex())
Expand All @@ -540,11 +568,10 @@ QList<Polygon> Polygon::splitConvexParts() const
score *= 4;
}
availableSplits << CandidateSplit{{halves[0], halves[1]}, score};
// break;
}
else
{
qDebug(" line %x...%x does not split to triangles",
qDebug(" line %x...%x fails to split",
poly.pointAt(j).id,
poly.pointAt(k).id);
}
Expand All @@ -556,8 +583,10 @@ QList<Polygon> Polygon::splitConvexParts() const
poly.isUnique(j), poly.isUnique(k));
}
}
if (availableSplits.size() >= maxAvailable) break; // That should be enough.
// if (wasSplit) break;
if (availableSplits.size() >= maxAvailable)
{
break; // That should be enough.
}
}
if (availableSplits.isEmpty())
{
Expand Down
2 changes: 1 addition & 1 deletion doomsday/apps/gloom/gloom/geo/polygon.h
Expand Up @@ -54,7 +54,7 @@ struct Polygon
bool isConvex() const;
QList<Polygon> splitConvexParts() const;
QVector<int> concavePoints() const;
Rangei findLoop() const;
Rangei findLoop(int findStartPos = 0) const;
bool hasDegenerateEdges() const;
bool isClockwiseWinding() const;
bool isUnique(int pos) const;
Expand Down
31 changes: 15 additions & 16 deletions doomsday/apps/gloom/gloom/world/mapimport.cpp
Expand Up @@ -279,6 +279,8 @@ DENG2_PIMPL_NOREF(MapImport)

bool import(const String &mapId)
{
qDebug() << "Importing map:" << mapId;

map.clear();

// Conversion from map units to meters.
Expand Down Expand Up @@ -614,10 +616,9 @@ DENG2_PIMPL_NOREF(MapImport)
return a.len < b.len;
});

if (candidates.size() > 0)
bool success = false;
foreach (const auto &connector, candidates)
{
const auto connector = candidates.front();

geo::Polygon::Points joined =
outer.polygon.points.mid(0, connector.outer + 1);
for (int i = 0; i < inner.polygon.size() + 1; ++i)
Expand All @@ -626,20 +627,18 @@ DENG2_PIMPL_NOREF(MapImport)
}
joined += outer.polygon.points.mid(connector.outer);

// Remove any duplicates.
// for (int i = 1; i < joined.size(); ++i)
// {
// if (joined[i].id == joined[i - 1].id)
// {
// joined.removeAt(i--);
// }
// }

outer.polygon.points = joined;
outer.update();
inner.clear();
// The outer contour must retain a clockwise winding.
const geo::Polygon joinedPoly{joined};
if (joinedPoly.isClockwiseWinding())
{
outer.polygon = joinedPoly;
outer.update();
inner.clear();
success = true;
break;
}
}
else
if (!success)
{
// Failure!
qDebug("Failed to join inner contour %i to its parent %i",
Expand Down
22 changes: 18 additions & 4 deletions doomsday/apps/gloom/src/editor.cpp
Expand Up @@ -999,9 +999,14 @@ DENG2_PIMPL(Editor)
{
if (!askSaveFile()) return;

if (String openPath = QFileDialog::getOpenFileName(
thisPublic, "Open File", filePath.fileNamePath(), "Gloom Map (*.gloommap)"))
QSettings st;
if (String openPath =
QFileDialog::getOpenFileName(thisPublic,
"Open File",
st.value("lastOpenPath", QDir::homePath()).toString(),
"Gloom Map (*.gloommap)"))
{
st.setValue("lastOpenPath", openPath.fileNamePath());
loadMap(openPath);
self().update();
}
Expand Down Expand Up @@ -1047,9 +1052,15 @@ DENG2_PIMPL(Editor)
{
askSaveFile();

QSettings st;
if (String openPath = QFileDialog::getOpenFileName(
thisPublic, "Import from WAD File", filePath.fileNamePath(), "WAD File (*.wad)"))
thisPublic,
"Import from WAD File",
st.value("lastImportPath", QDir::homePath()).toString(),
"WAD File (*.wad)"))
{
st.setValue("lastImportPath", openPath.fileNamePath());

String path = FS::accessNativeLocation(openPath);
if (const DataBundle *bundle = FS::tryLocate<const DataBundle>(path))
{
Expand Down Expand Up @@ -1109,7 +1120,10 @@ DENG2_PIMPL(Editor)

void setWindowTitle(const String &text)
{
self().parentWidget()->setWindowTitle(text);
if (self().parentWidget())
{
self().parentWidget()->setWindowTitle(text);
}
}

void resetState()
Expand Down

0 comments on commit e88cd42

Please sign in to comment.