Skip to content

Commit

Permalink
#5382: WIP welding code. Add parameterised unit test, welding patch 1…
Browse files Browse the repository at this point in the history
… in the test map with a set of other patches
  • Loading branch information
codereader committed Dec 8, 2020
1 parent aa0b410 commit 8160d63
Show file tree
Hide file tree
Showing 3 changed files with 520 additions and 13 deletions.
76 changes: 70 additions & 6 deletions radiantcore/patch/algorithm/General.cpp
Expand Up @@ -424,28 +424,46 @@ namespace
{

// Returns true if all the elements in the given sequences are equal
inline bool isEqual(const PatchControlIterator& sequence1, const PatchControlIterator& sequence2)
inline bool isEqual(const PatchControlIterator& sequence1, const PatchControlIterator& sequence2, double epsilon)
{
// If the iterators are invalid from the start, return false
if (!sequence1.isValid() || !sequence2.isValid())
{
rMessage() << "Sequences are not valid" << std::endl;
return false;
}

for (auto p1 = sequence1, p2 = sequence2; p1.isValid() && p2.isValid(); ++p1, ++p2)
{
if (p1->vertex != p2->vertex)
rMessage() << "P1: " << p1->vertex << ", P2: " << p2->vertex << std::endl;

if (!p1->vertex.isEqual(p2->vertex, epsilon))
{
rMessage() << "Sequences are not equal" << std::endl;
return false;
}
}

rMessage() << "Sequences are equal" << std::endl;

return true;
}

// Copies all values from source to target, until the source sequence is depleted
// Returns the new position of the target iterator
inline void assignPatchControls(const PatchControlIterator& source, PatchControlIterator& target)
{
auto& t = target;
for (auto s = source; s.isValid() && t.isValid(); ++s, ++t)
{
t->vertex = s->vertex;
t->texcoord = s->texcoord;
}
}

}

PatchNodePtr createdMergedPatch(const PatchNodePtr& patchNode1, const PatchNodePtr& patchNode2)
scene::INodePtr createdMergedPatch(const PatchNodePtr& patchNode1, const PatchNodePtr& patchNode2)
{
constexpr double WELD_EPSILON = 0.001;

Expand Down Expand Up @@ -473,11 +491,50 @@ PatchNodePtr createdMergedPatch(const PatchNodePtr& patchNode1, const PatchNodeP
SinglePatchRowIterator patch2FirstRow(patch2, 0);
SinglePatchRowIterator patch2LastRow(patch2, patch2.getWidth() - 1);

if (isEqual(patch1FirstRow, patch2FirstRow))
rMessage() << "Comparing P1FirstRow to P2FirstRow" << std::endl;
if (isEqual(patch1FirstRow, patch2FirstRow, WELD_EPSILON))
{
auto newPatchNode = GlobalPatchModule().createPatch(patch1.subdivisionsFixed() ? PatchDefType::Def3 : PatchDefType::Def2);
auto& newPatch = std::dynamic_pointer_cast<IPatchNode>(newPatchNode)->getPatch();
newPatch.setDims(patch1.getWidth(), patch1.getHeight() + patch2.getHeight() - 1);

// prepend
// use rows of other patch
}

rMessage() << "Comparing P1FirstRow to P2LastRow" << std::endl;
if (isEqual(patch1FirstRow, patch2LastRow, WELD_EPSILON))
{
// prepend
// use rows of other patch from end
}

rMessage() << "Comparing P1LastRow to P2FirstRow" << std::endl;
if (isEqual(patch1LastRow, patch2FirstRow, WELD_EPSILON))
{
auto sceneNode = GlobalPatchModule().createPatch(patch1.subdivisionsFixed() ? PatchDefType::Def3 : PatchDefType::Def2);
auto& newPatch = std::dynamic_pointer_cast<IPatchNode>(sceneNode)->getPatch();
newPatch.setDims(patch1.getWidth(), patch1.getHeight() + patch2.getHeight() - 1);

RowWisePatchIterator p1(patch1);
RowWisePatchIterator p2(patch2, 1, patch2.getWidth() - 1); // skip the first row of the second patch
RowWisePatchIterator target(newPatch);

assignPatchControls(p1, target);
assignPatchControls(p2, target);

newPatch.controlPointsChanged();

return sceneNode;
}

rMessage() << "Comparing P1LastRow to P2LastRow" << std::endl;
if (isEqual(patch1LastRow, patch2LastRow, WELD_EPSILON))
{
// append
// use rows of other patch from end
}
#if 0
row1 = 0;
row2 = 0;

Expand Down Expand Up @@ -553,8 +610,11 @@ PatchNodePtr createdMergedPatch(const PatchNodePtr& patchNode1, const PatchNodeP
break;
}
}
#endif
}

return scene::INodePtr();

if (patch1.getWidth() == patch2.getHeight())
{
row1 = 0;
Expand Down Expand Up @@ -798,14 +858,18 @@ PatchNodePtr createdMergedPatch(const PatchNodePtr& patchNode1, const PatchNodeP
void weldPatches(const PatchNodePtr& patchNode1, const PatchNodePtr& patchNode2)
{
auto mergedPatch = createdMergedPatch(patchNode1, patchNode2);
assert(mergedPatch);

if (!mergedPatch)
{
throw cmd::ExecutionFailure(_("Failed to weld patches."));
}

patchNode1->getParent()->addChildNode(mergedPatch);

mergedPatch->assignToLayers(patchNode1->getLayers());
// TODO: selection grouping

mergedPatch->getPatch().scaleTextureNaturally();
std::dynamic_pointer_cast<IPatchNode>(mergedPatch)->getPatch().scaleTextureNaturally();

Node_setSelected(mergedPatch, true);

Expand Down
41 changes: 34 additions & 7 deletions test/PatchWelding.cpp
Expand Up @@ -11,14 +11,19 @@ namespace test

using PatchWeldingTest = RadiantTest;

class PatchWelding3x3 :
public PatchWeldingTest,
public testing::WithParamInterface<const char*>
{};

namespace
{

inline scene::INodePtr findPatchWithNumber(const std::string& number)
{
return algorithm::findFirstPatchWithMaterial(GlobalMapModule().getRoot(), "textures/numbers/" + number);
}

namespace
{

void performPatchWeldingTest(const std::string& number1, const std::string& number2, int expectedRows, int expectedCols)
{
auto firstPatch = findPatchWithNumber(number1);
Expand Down Expand Up @@ -64,12 +69,25 @@ void assumePatchWeldingFails(const std::string& number1, const std::string& numb

}

// Patch 1 = 3x3, Patch 2 = 3x3 to the "left"
TEST_F(PatchWeldingTest, WeldPatches1And2)
// Patch 1 is sharing its first row with another patch
TEST_P(PatchWelding3x3, WeldPatch1WithOther3x3)
{
loadMap("weld_patches.mapx");
loadMap("weld_patches2.mapx");

auto otherPatch = GetParam();

// Welding patches 1 and 2 should produce a 3rows x 5cols patch
// Welding should produce a 5rows x 3cols patch
performPatchWeldingTest("1", otherPatch, 5, 3);
}

INSTANTIATE_TEST_CASE_P(WeldPatch1WithOther3x3, PatchWelding3x3, testing::Values("2", "3", "4", "5"));

#if 0
TEST_F(PatchWeldingTest, Weld3x3Patches1And5)
{
loadMap("weld_patches2.mapx");

// Welding should produce a 3rows x 5cols patch
performPatchWeldingTest("1", "2", 3, 5);
}

Expand Down Expand Up @@ -163,4 +181,13 @@ TEST_F(PatchWeldingTest, WeldPatches11And12)
performPatchWeldingTest("11", "12", 5, 9);
}

// Patches 13 are 14 are matching at first row : first row
TEST_F(PatchWeldingTest, WeldPatches13And14)
{
loadMap("weld_patches.mapx");

// Welding the two cylinders produce a 5rows x 3cols patch
performPatchWeldingTest("13", "14", 5, 3);
}
#endif
}

0 comments on commit 8160d63

Please sign in to comment.