Skip to content

Commit 3d1eae8

Browse files
committed
Merge branch 'master' of https://github.com/MeshInspector/MeshLib into dev
2 parents af4136e + 2a8ef80 commit 3d1eae8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1309
-486
lines changed

.github/workflows/build-test-distribute.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ jobs:
336336
collect-stats:
337337
timeout-minutes: 5
338338
runs-on: aws-micro
339-
needs: [ upload-distributions ]
339+
needs: [ config, upload-distributions ]
340340
if: ${{ always() && needs.config.outputs.internal_build == 'true' }}
341341
continue-on-error: true
342342
steps:
@@ -349,6 +349,16 @@ jobs:
349349
pattern: RunnerSysStats*
350350
merge-multiple: true
351351

352+
- uses: aws-actions/configure-aws-credentials@v4
353+
id: aws-creds
354+
with:
355+
aws-region: us-east-1
356+
role-to-assume: ${{ secrets.AWS_CI_STAT_API_ROLE_ARN }}
357+
output-credentials: true
358+
359+
- name: Install dependencies
360+
run: python3 -m pip install boto3 botocore
361+
352362
- name: Collect stats
353363
env:
354364
CI_STATS_AUTH_TOKEN: ${{ secrets.CI_STATS_AUTH_TOKEN }}

.github/workflows/build-test-macos.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ jobs:
120120
121121
- name: Run Start-and-Exit Tests
122122
timeout-minutes: 3
123-
run: MR_LOCAL_RESOURCES=1 ./build/${{ matrix.config }}/bin/MeshViewer -tryHidden -noEventLoop -unloadPluginsAtEnd
123+
run: MR_LOCAL_RESOURCES=1 ./build/${{ matrix.config }}/bin/MeshViewer.app/Contents/MacOS/MeshViewer -tryHidden -noEventLoop -unloadPluginsAtEnd
124124

125125
- name: Unit Tests
126126
run: ./build/${{ matrix.config }}/bin/MRTest

examples/python-examples/MeshOffsetWeighted.dox.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
# ===params
1717

18-
params = mrmeshpy.WeightedPointsShellParametersMetric()
18+
params = mrmeshpy.WeightedShell.ParametersMetric()
1919
# Algorithm is voxel based, voxel size affects performance and form of result mesh
2020
params.voxelSize = mrmeshpy.suggestVoxelSize(mesh, 10000)
2121
# common basic offset applied for all point
@@ -24,6 +24,6 @@
2424
params.dist.maxWeight = max(scalars.vec) # should always have maximum between weights provided
2525

2626
# ===offset
27-
res = mrmeshpy.weightedMeshShell(mesh, scalars, params)
27+
res = mrmeshpy.WeightedShell.meshShell(mesh, scalars, params)
2828

2929
mrmeshpy.saveMesh(res, "offset_weighted.ctm")

scripts/devops/collect_ci_stats.py

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66
from pathlib import Path
77
from typing import List
88

9+
import boto3
10+
from botocore.auth import SigV4Auth
11+
from botocore.awsrequest import AWSRequest
912
import requests
1013

14+
API_URL = "https://api.meshinspector.com/ci-stats/v2/log"
15+
1116
def parse_iso8601(s):
1217
return datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S%z')
1318

@@ -76,6 +81,23 @@ def fetch_jobs(repo: str, run_id: str):
7681
'X-GitHub-Api-Version': '2022-11-28',
7782
})
7883

84+
def sign_api_request(url, method, headers, body, region, service):
85+
# Use the credentials from the assumed role
86+
session = boto3.Session()
87+
credentials = session.get_credentials().get_frozen_credentials()
88+
89+
request = AWSRequest(
90+
method=method,
91+
url=url,
92+
headers=headers,
93+
data=json.dumps(body)
94+
)
95+
96+
# Sign the request with the SigV4Auth class
97+
SigV4Auth(credentials, service, region).add_auth(request)
98+
99+
return request
100+
79101
if __name__ == "__main__":
80102
branch = os.environ.get('GIT_BRANCH')
81103
commit = os.environ.get('GIT_COMMIT')
@@ -95,8 +117,29 @@ def fetch_jobs(repo: str, run_id: str):
95117
}
96118
pprint.pp(result, indent=2, width=150)
97119

98-
resp = requests.post("https://api.meshinspector.com/ci-stats/v1/log", json=result, headers={
99-
'Authorization': f'Bearer {os.environ.get("CI_STATS_AUTH_TOKEN")}',
100-
})
101-
if resp.status_code != 200:
102-
raise RuntimeError(f'{resp.status_code}: {resp.text}')
120+
headers = {
121+
'Content-Type': 'application/json',
122+
}
123+
124+
if os.environ.get("CI_STATS_AUTH_TOKEN"):
125+
headers['Authorization'] = f'Bearer {os.environ.get("CI_STATS_AUTH_TOKEN")}'
126+
127+
signed_request = sign_api_request(
128+
API_URL,
129+
'POST',
130+
headers,
131+
result,
132+
'us-east-1',
133+
'execute-api' # Service name for API Gateway
134+
)
135+
136+
response = requests.post(
137+
API_URL,
138+
headers=dict(signed_request.headers.items()), # Use signed headers
139+
data=signed_request.body
140+
)
141+
142+
if response.status_code == 200:
143+
print("Successfully sent the CI stats to the API")
144+
else:
145+
raise RuntimeError(f'{response.status_code}: {response.text}')

source/MRMesh/MRBooleanOperation.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ bool preparePart( const Mesh& origin, std::vector<EdgePath>& cutPaths, Mesh& out
111111
auto compsMap = MeshComponents::getAllComponentsMap( origin );
112112
leftPart = preparePart( origin, compsMap, leftPart, otherMesh, needInsidePart, originIsA, rigidB2A, mergeAllNonIntersectingComponents, intParams );
113113

114-
outMesh.addMeshPart( { origin, &leftPart }, needFlip, {}, {},
115-
HashToVectorMappingConverter( origin.topology, fMapPtr, vMapPtr, eMapPtr ).getPartMapping() );
114+
outMesh.addMeshPart( { origin, &leftPart }, needFlip, {}, {}, Src2TgtMaps( fMapPtr, vMapPtr, eMapPtr ) );
116115

117116
for ( auto& path : cutPaths )
118117
for ( auto& e : path )
@@ -145,11 +144,9 @@ void connectPreparedParts( Mesh& partA, Mesh& partB, bool pathsHaveLeftHole,
145144
else
146145
{
147146
if ( !pathsHaveLeftHole )
148-
partA.addMeshPart( partB, false, pathsA, pathsB,
149-
HashToVectorMappingConverter( partB.topology, fMapNewPtr, vMapNewPtr, eMapNewPtr ).getPartMapping() );
147+
partA.addMeshPart( partB, false, pathsA, pathsB, Src2TgtMaps( fMapNewPtr, vMapNewPtr, eMapNewPtr ) );
150148
else
151-
partB.addMeshPart( partA, false, pathsB, pathsA,
152-
HashToVectorMappingConverter( partA.topology, fMapNewPtr, vMapNewPtr, eMapNewPtr ).getPartMapping() );
149+
partB.addMeshPart( partA, false, pathsB, pathsA, Src2TgtMaps( fMapNewPtr, vMapNewPtr, eMapNewPtr ) );
153150
}
154151

155152
if ( mapper )
@@ -197,24 +194,24 @@ Mesh doTrivialBooleanOperation( Mesh&& meshACut, Mesh&& meshBCut, BooleanOperati
197194
bPartFbs = preparePart( meshBCut, bComponentsMap, {}, meshACut, true, false, rigidB2A, mergeAllNonIntersectingComponents, intParams );
198195
taskGroup.wait();
199196

200-
if ( aPartFbs.count() != 0 )
197+
if ( aPartFbs.any() )
201198
{
202199
FaceMap* fMapPtr = mapper ? &mapper->maps[int( BooleanResultMapper::MapObject::A )].cut2newFaces : nullptr;
203200
WholeEdgeMap* eMapPtr = mapper ? &mapper->maps[int( BooleanResultMapper::MapObject::A )].old2newEdges : nullptr;
204201
VertMap* vMapPtr = mapper ? &mapper->maps[int( BooleanResultMapper::MapObject::A )].old2newVerts : nullptr;
205202

206203
aPart.addMeshPart( { meshACut, &aPartFbs }, operation == BooleanOperation::DifferenceBA,
207-
{}, {}, HashToVectorMappingConverter( meshACut.topology, fMapPtr, vMapPtr, eMapPtr ).getPartMapping() );
204+
{}, {}, Src2TgtMaps( fMapPtr, vMapPtr, eMapPtr ) );
208205
}
209206

210-
if ( bPartFbs.count() != 0 )
207+
if ( bPartFbs.any() )
211208
{
212209
FaceMap* fMapPtr = mapper ? &mapper->maps[int( BooleanResultMapper::MapObject::B )].cut2newFaces : nullptr;
213210
WholeEdgeMap* eMapPtr = mapper ? &mapper->maps[int( BooleanResultMapper::MapObject::B )].old2newEdges : nullptr;
214211
VertMap* vMapPtr = mapper ? &mapper->maps[int( BooleanResultMapper::MapObject::B )].old2newVerts : nullptr;
215212

216213
bPart.addMeshPart( { meshBCut, &bPartFbs }, operation == BooleanOperation::DifferenceAB,
217-
{}, {}, HashToVectorMappingConverter( meshBCut.topology, fMapPtr, vMapPtr, eMapPtr ).getPartMapping() );
214+
{}, {}, Src2TgtMaps( fMapPtr, vMapPtr, eMapPtr ) );
218215
}
219216

220217
connectPreparedParts( aPart, bPart, false, {}, {}, rigidB2A, mapper );

source/MRMesh/MRChangeXfAction.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,24 @@ namespace MR
1212
class ChangeXfAction : public HistoryAction
1313
{
1414
public:
15-
/// Constructed from original obj
15+
/// use this constructor to remember object's transformation before making any changes in it
1616
ChangeXfAction( const std::string& name, const std::shared_ptr<Object>& obj ) :
1717
obj_{ obj },
1818
xf_{ obj->xf() },
1919
name_{ name }
2020
{
2121
}
2222

23+
/// use this constructor to remember object's transformation and immediately set new mesh
24+
ChangeXfAction( const std::string& name, const std::shared_ptr<Object>& obj, const AffineXf3f& newXf ) :
25+
obj_{ obj },
26+
xf_{ obj->xf() },
27+
name_{ name }
28+
{
29+
if ( obj_ )
30+
obj_->setXf( newXf );
31+
}
32+
2333
virtual std::string name() const override
2434
{
2535
return name_;
@@ -39,10 +49,15 @@ class ChangeXfAction : public HistoryAction
3949
return name_.capacity();
4050
}
4151

52+
const std::shared_ptr<Object> & obj() const
53+
{
54+
return obj_;
55+
}
56+
4257
private:
4358
std::shared_ptr<Object> obj_;
4459
AffineXf3f xf_;
4560
std::string name_;
4661
};
4762

48-
}
63+
} //namespace MR

source/MRMesh/MRClosestWeightedPoint.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,13 @@ MeshPointAndDistance findClosestWeightedMeshPoint( const Vector3f& loc,
163163
const auto mtp = MeshTriPoint{ mesh.topology.edgeWithLeft( f ), c->tp };
164164
const MeshPointAndDistance candidate
165165
{
166+
.loc = loc,
166167
.mtp = mtp,
167168
.eucledeanDist = distance( loc, c->pos ),
168169
.w = c->w,
169170
.bidirectionalOrOutside = params.bidirectionalMode || dot( mesh.pseudonormal( mtp ), loc - c->pos ) >= 0
170171
};
171-
if ( candidate.innerDist() < res.innerDist() )
172+
if ( candidate < res )
172173
{
173174
assert( candidate.bidirDist() < params.maxBidirDist );
174175
res = candidate;

source/MRMesh/MRClosestWeightedPoint.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ struct PointAndDistance
2323

2424
struct MeshPointAndDistance
2525
{
26-
/// a point on mesh in barycentric representation
26+
/// point location
27+
Vector3f loc;
28+
29+
/// the corresponding point on mesh in barycentric representation
2730
MeshTriPoint mtp;
2831

2932
/// euclidean distance from input location to mtp
@@ -35,6 +38,7 @@ struct MeshPointAndDistance
3538
/// either
3639
/// 1) bidirectional distances are computed, or
3740
/// 2) input location is locally outside of the surface (by pseudonormal)
41+
/// used for optimization
3842
bool bidirectionalOrOutside = true;
3943

4044
/// bidirectional distance from input location to mtp considering point's weight
@@ -51,11 +55,15 @@ struct MeshPointAndDistance
5155
return ( bidirectionalOrOutside ? eucledeanDist : -eucledeanDist ) - w;
5256
}
5357

54-
/// this distance is used internally to find the best surface point, which has the smallest inner distance;
55-
/// innerDist() grows in both directions of the surface unlike weightedDist()
56-
[[nodiscard]] float innerDist() const
58+
/// comparison telling which point is closer to the location
59+
auto operator <=> ( const MeshPointAndDistance& other ) const
5760
{
58-
return eucledeanDist + ( bidirectionalOrOutside ? -w : w );
61+
if ( bidirectionalOrOutside && other.bidirectionalOrOutside )
62+
return eucledeanDist - w <=> other.eucledeanDist - other.w;
63+
if ( bidirectionalOrOutside != other.bidirectionalOrOutside )
64+
return eucledeanDist <=> other.eucledeanDist;
65+
return eucledeanDist + ( bidirectionalOrOutside ? -w : w ) <=>
66+
other.eucledeanDist + ( other.bidirectionalOrOutside ? -other.w : other.w );
5967
}
6068

6169
/// check for validity, otherwise there is no point closer than maxBidirDist

source/MRMesh/MRContoursCut.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,6 @@ struct PreCutResult
7070
std::vector<std::vector<PathsEdgeIndex>> oldEdgesInfo;
7171
};
7272

73-
bool isClosed( const ContinuousContour& contour )
74-
{
75-
return contour.size() > 1 &&
76-
contour.front().isEdgeATriB == contour.back().isEdgeATriB &&
77-
contour.front().edge.undirected() == contour.back().edge.undirected() &&
78-
contour.front().tri == contour.back().tri;
79-
}
80-
8173
enum class TrianglesSortRes
8274
{
8375
Undetermined, // triangles positions cannot be determined
@@ -2167,7 +2159,7 @@ CutMeshResult cutMesh( Mesh& mesh, const OneMeshContours& contours, const CutMes
21672159
fixOrphans( mesh, preRes.paths, preRes.removedFaces, params.new2OldMap, params.new2oldEdgesMap );
21682160

21692161
res.fbsWithContourIntersections = getBadFacesAfterCut( mesh.topology, preRes, preRes.removedFaces );
2170-
if ( params.forceFillMode == CutMeshParameters::ForceFill::None && res.fbsWithContourIntersections.count() > 0 )
2162+
if ( params.forceFillMode == CutMeshParameters::ForceFill::None && res.fbsWithContourIntersections.any() )
21712163
return res;
21722164

21732165
// find one edge for every hole to fill

source/MRMesh/MRFixSelfIntersections.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,17 +230,22 @@ Expected<void> fix( Mesh& mesh, const Settings& settings )
230230
// Helper function to find own self-intersections on a mesh part
231231
static Expected<FaceBitSet> findSelfCollidingTrianglesBSForPart( Mesh& mesh, const FaceBitSet& part, ProgressCallback cb, bool touchIsIntersection )
232232
{
233-
FaceMap tgt2srcFaceMap;
233+
FaceMapOrHashMap tgt2srcFaces;
234234
PartMapping mapping;
235-
mapping.tgt2srcFaceMap = &tgt2srcFaceMap;
235+
mapping.tgt2srcFaces = &tgt2srcFaces;
236236
Mesh partMesh = mesh.cloneRegion( part, false, mapping );
237237
// Faster than searching in mesh part due to AABB tree rebuild
238238
auto res = findSelfCollidingTrianglesBS( { partMesh }, cb, nullptr, touchIsIntersection );
239239
if ( !res.has_value() )
240240
return unexpected( res.error() );
241241
FaceBitSet result( mesh.topology.lastValidFace() + 1 );
242-
for ( FaceId f : *res )
243-
result.set( tgt2srcFaceMap[f] );
242+
if ( auto map = tgt2srcFaces.getMap() )
243+
{
244+
for ( FaceId f : *res )
245+
result.set( (*map)[f] );
246+
}
247+
else
248+
assert( false );
244249
return result;
245250
}
246251

0 commit comments

Comments
 (0)