topologicpy 0.7.63__py3-none-any.whl → 0.7.65__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- topologicpy/Face.py +151 -1
- topologicpy/Wire.py +7 -4
- topologicpy/version.py +1 -1
- topologicpy-0.7.65.dist-info/LICENSE +16 -0
- {topologicpy-0.7.63.dist-info → topologicpy-0.7.65.dist-info}/METADATA +12 -17
- {topologicpy-0.7.63.dist-info → topologicpy-0.7.65.dist-info}/RECORD +8 -8
- topologicpy-0.7.63.dist-info/LICENSE +0 -21
- {topologicpy-0.7.63.dist-info → topologicpy-0.7.65.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.63.dist-info → topologicpy-0.7.65.dist-info}/top_level.txt +0 -0
topologicpy/Face.py
CHANGED
@@ -399,7 +399,157 @@ class Face():
|
|
399
399
|
print("Face.ByOffset - Warning: Could not create face from wires. Returning None.")
|
400
400
|
return None
|
401
401
|
return return_face
|
402
|
-
|
402
|
+
|
403
|
+
@staticmethod
|
404
|
+
def ByOffsetArea(face,
|
405
|
+
area,
|
406
|
+
offsetKey="offset",
|
407
|
+
minOffsetKey="minOffset",
|
408
|
+
maxOffsetKey="maxOffset",
|
409
|
+
defaultMinOffset=0,
|
410
|
+
defaultMaxOffset=1,
|
411
|
+
maxIterations = 1,
|
412
|
+
tolerance=0.0001,
|
413
|
+
silent = False,
|
414
|
+
numWorkers = None):
|
415
|
+
"""
|
416
|
+
Creates an offset face from the input face based on the input area.
|
417
|
+
|
418
|
+
Parameters
|
419
|
+
----------
|
420
|
+
face : topologic_core.Face
|
421
|
+
The input face.
|
422
|
+
area : float
|
423
|
+
The desired area of the created face.
|
424
|
+
offsetKey : str , optional
|
425
|
+
The edge dictionary key under which to store the offset value. The default is "offset".
|
426
|
+
minOffsetKey : str , optional
|
427
|
+
The edge dictionary key under which to find the desired minimum edge offset value. If a value cannot be found, the defaultMinOffset input parameter value is used instead. The default is "minOffset".
|
428
|
+
maxOffsetKey : str , optional
|
429
|
+
The edge dictionary key under which to find the desired maximum edge offset value. If a value cannot be found, the defaultMaxOffset input parameter value is used instead. The default is "maxOffset".
|
430
|
+
defaultMinOffset : float , optional
|
431
|
+
The desired minimum edge offset distance. The default is 0.
|
432
|
+
defaultMaxOffset : float , optional
|
433
|
+
The desired maximum edge offset distance. The default is 1.
|
434
|
+
maxIterations: int , optional
|
435
|
+
The desired maximum number of iterations to attempt to converge on a solution. The default is 1.
|
436
|
+
tolerance : float , optional
|
437
|
+
The desired tolerance. The default is 0.0001.
|
438
|
+
silent : bool , optional
|
439
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
440
|
+
numWorkers : int , optional
|
441
|
+
Number of workers run in parallel to process. If you set it to 1, no parallel processing will take place.
|
442
|
+
The default is None which causes the algorithm to use twice the number of cpu cores in the host computer.
|
443
|
+
|
444
|
+
Returns
|
445
|
+
-------
|
446
|
+
topologic_core.Face
|
447
|
+
The created face.
|
448
|
+
|
449
|
+
"""
|
450
|
+
from topologicpy.Wire import Wire
|
451
|
+
from topologicpy.Face import Face
|
452
|
+
from topologicpy.Topology import Topology
|
453
|
+
from topologicpy.Dictionary import Dictionary
|
454
|
+
import numpy as np
|
455
|
+
from scipy.optimize import minimize
|
456
|
+
|
457
|
+
def compute_offset_amounts(face,
|
458
|
+
area,
|
459
|
+
offsetKey="offset",
|
460
|
+
minOffsetKey="minOffset",
|
461
|
+
maxOffsetKey="maxOffset",
|
462
|
+
defaultMinOffset=0,
|
463
|
+
defaultMaxOffset=1,
|
464
|
+
maxIterations = 1,
|
465
|
+
tolerance=0.0001):
|
466
|
+
|
467
|
+
initial_offsets = []
|
468
|
+
bounds = []
|
469
|
+
for edge in edges:
|
470
|
+
d = Topology.Dictionary(edge)
|
471
|
+
minOffset = Dictionary.ValueAtKey(d, minOffsetKey) or defaultMinOffset
|
472
|
+
maxOffset = Dictionary.ValueAtKey(d, maxOffsetKey) or defaultMaxOffset
|
473
|
+
# Initial guess: small negative offsets to shrink the polygon, within the constraints
|
474
|
+
initial_offsets.append((minOffset + maxOffset) / 2)
|
475
|
+
# Bounds based on the constraints for each edge
|
476
|
+
bounds.append((minOffset, maxOffset))
|
477
|
+
|
478
|
+
# Convert initial_offsets to np.array for efficiency
|
479
|
+
initial_offsets = np.array(initial_offsets)
|
480
|
+
iteration_count = [0] # List to act as a mutable counter
|
481
|
+
|
482
|
+
def objective_function(offsets):
|
483
|
+
for i, edge in enumerate(edges):
|
484
|
+
d = Topology.Dictionary(edge)
|
485
|
+
d = Dictionary.SetValueAtKey(d, offsetKey, offsets[i])
|
486
|
+
edge = Topology.SetDictionary(edge, d)
|
487
|
+
|
488
|
+
# Offset the wire
|
489
|
+
new_face = Face.ByOffset(face, offsetKey=offsetKey, silent=silent, numWorkers=numWorkers)
|
490
|
+
# Check for an illegal wire. In that case, return a very large loss value.
|
491
|
+
if not Topology.IsInstance(new_face, "Face"):
|
492
|
+
return (float("inf"))
|
493
|
+
# Calculate the area of the new wire/face
|
494
|
+
new_area = Face.Area(new_face)
|
495
|
+
|
496
|
+
# The objective is the difference between the target hole area and the actual hole area
|
497
|
+
# We want this difference to be as close to 0 as possible
|
498
|
+
loss = (new_area - area) ** 2
|
499
|
+
# If the loss is less than the tolerance, accept the result and return a loss of 0.
|
500
|
+
if loss < tolerance:
|
501
|
+
return 0
|
502
|
+
# Otherwise, return the actual loss value.
|
503
|
+
return loss
|
504
|
+
|
505
|
+
# Callback function to track and display iteration number
|
506
|
+
def iteration_callback(xk):
|
507
|
+
iteration_count[0] += 1 # Increment the counter
|
508
|
+
if not silent:
|
509
|
+
print(f"Face.ByOffsetArea - Information: Iteration {iteration_count[0]}")
|
510
|
+
|
511
|
+
# Use scipy optimization/minimize to find the correct offsets, respecting the min/max bounds
|
512
|
+
result = minimize(objective_function,
|
513
|
+
initial_offsets,
|
514
|
+
method = "Powell",
|
515
|
+
bounds=bounds,
|
516
|
+
options={ 'maxiter': maxIterations},
|
517
|
+
callback=iteration_callback
|
518
|
+
)
|
519
|
+
|
520
|
+
# Return the offsets
|
521
|
+
return result.x
|
522
|
+
|
523
|
+
if not Topology.IsInstance(face, "Face"):
|
524
|
+
if not silent:
|
525
|
+
print("Face.OffsetByArea - Error: The input face parameter is not a valid face. Returning None.")
|
526
|
+
return None
|
527
|
+
|
528
|
+
edges = Topology.Edges(face)
|
529
|
+
# Compute the offset amounts
|
530
|
+
offsets = compute_offset_amounts(face,
|
531
|
+
area = area,
|
532
|
+
offsetKey = offsetKey,
|
533
|
+
minOffsetKey = minOffsetKey,
|
534
|
+
maxOffsetKey = maxOffsetKey,
|
535
|
+
defaultMinOffset = defaultMinOffset,
|
536
|
+
defaultMaxOffset = defaultMaxOffset,
|
537
|
+
maxIterations = maxIterations,
|
538
|
+
tolerance = tolerance)
|
539
|
+
# Set the edge dictionaries correctly according to the specified offsetKey
|
540
|
+
for i, edge in enumerate(edges):
|
541
|
+
d = Topology.Dictionary(edge)
|
542
|
+
d = Dictionary.SetValueAtKey(d, offsetKey, offsets[i])
|
543
|
+
edge = Topology.SetDictionary(edge, d)
|
544
|
+
|
545
|
+
# Offset the face
|
546
|
+
return_face = Face.ByOffset(face, offsetKey=offsetKey, silent=silent, numWorkers=numWorkers)
|
547
|
+
if not Topology.IsInstance(face, "Face"):
|
548
|
+
if not silent:
|
549
|
+
print("Face.OffsetByArea - Error: Could not create the offset face. Returning None.")
|
550
|
+
return None
|
551
|
+
return return_face
|
552
|
+
|
403
553
|
@staticmethod
|
404
554
|
def ByShell(shell, origin= None, angTolerance: float = 0.1, tolerance: float = 0.0001, silent=False):
|
405
555
|
"""
|
topologicpy/Wire.py
CHANGED
@@ -694,7 +694,8 @@ class Wire():
|
|
694
694
|
defaultMaxOffset=1,
|
695
695
|
maxIterations = 1,
|
696
696
|
tolerance=0.0001,
|
697
|
-
silent = False
|
697
|
+
silent = False,
|
698
|
+
numWorkers = None):
|
698
699
|
"""
|
699
700
|
Creates an offset wire from the input wire based on the input area.
|
700
701
|
|
@@ -720,6 +721,9 @@ class Wire():
|
|
720
721
|
The desired tolerance. The default is 0.0001.
|
721
722
|
silent : bool , optional
|
722
723
|
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
724
|
+
numWorkers : int , optional
|
725
|
+
Number of workers run in parallel to process. If you set it to 1, no parallel processing will take place.
|
726
|
+
The default is None which causes the algorithm to use twice the number of cpu cores in the host computer.
|
723
727
|
|
724
728
|
Returns
|
725
729
|
-------
|
@@ -742,7 +746,6 @@ class Wire():
|
|
742
746
|
defaultMinOffset=0,
|
743
747
|
defaultMaxOffset=1,
|
744
748
|
maxIterations = 10000,
|
745
|
-
maxTime = 10,
|
746
749
|
tolerance=0.0001):
|
747
750
|
|
748
751
|
initial_offsets = []
|
@@ -767,7 +770,7 @@ class Wire():
|
|
767
770
|
edge = Topology.SetDictionary(edge, d)
|
768
771
|
|
769
772
|
# Offset the wire
|
770
|
-
new_wire = Wire.ByOffset(wire, offsetKey=offsetKey, silent=silent)
|
773
|
+
new_wire = Wire.ByOffset(wire, offsetKey=offsetKey, silent=silent, numWorkers=numWorkers)
|
771
774
|
# Check for an illegal wire. In that case, return a very large loss value.
|
772
775
|
if not Topology.IsInstance(new_wire, "Wire"):
|
773
776
|
return (float("inf"))
|
@@ -839,7 +842,7 @@ class Wire():
|
|
839
842
|
edge = Topology.SetDictionary(edge, d)
|
840
843
|
|
841
844
|
# Offset the wire
|
842
|
-
return_wire = Wire.ByOffset(wire, offsetKey=offsetKey, silent=silent)
|
845
|
+
return_wire = Wire.ByOffset(wire, offsetKey=offsetKey, silent=silent, numWorkers=numWorkers)
|
843
846
|
if not Topology.IsInstance(wire, "Wire"):
|
844
847
|
if not silent:
|
845
848
|
print("Wire.OffsetByArea - Error: Could not create the offset wire. Returning None.")
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.7.
|
1
|
+
__version__ = '0.7.65'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
AGPL v3 License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Wassim Jabi
|
4
|
+
|
5
|
+
This program is free software: you can redistribute it and/or modify it under
|
6
|
+
the terms of the GNU Affero General Public License as published by the Free Software
|
7
|
+
Foundation, either version 3 of the License, or (at your option) any later
|
8
|
+
version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful, but WITHOUT
|
11
|
+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
12
|
+
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
13
|
+
details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU Affero General Public License along with
|
16
|
+
this program. If not, see <https://www.gnu.org/licenses/>.
|
@@ -1,29 +1,24 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.7.
|
3
|
+
Version: 0.7.65
|
4
4
|
Summary: An AI-Powered Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
|
5
5
|
Author-email: Wassim Jabi <wassim.jabi@gmail.com>
|
6
|
-
License:
|
6
|
+
License: AGPL v3 License
|
7
7
|
|
8
8
|
Copyright (c) 2024 Wassim Jabi
|
9
9
|
|
10
|
-
|
11
|
-
of
|
12
|
-
|
13
|
-
|
14
|
-
copies of the Software, and to permit persons to whom the Software is
|
15
|
-
furnished to do so, subject to the following conditions:
|
10
|
+
This program is free software: you can redistribute it and/or modify it under
|
11
|
+
the terms of the GNU Affero General Public License as published by the Free Software
|
12
|
+
Foundation, either version 3 of the License, or (at your option) any later
|
13
|
+
version.
|
16
14
|
|
17
|
-
|
18
|
-
|
15
|
+
This program is distributed in the hope that it will be useful, but WITHOUT
|
16
|
+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
18
|
+
details.
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
23
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
24
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
25
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
26
|
-
SOFTWARE.
|
20
|
+
You should have received a copy of the GNU Affero General Public License along with
|
21
|
+
this program. If not, see <https://www.gnu.org/licenses/>.
|
27
22
|
|
28
23
|
Project-URL: Homepage, https://github.com/wassimj/TopologicPy
|
29
24
|
Project-URL: Bug Tracker, https://github.com/wassimj/TopologicPy/issues
|
@@ -10,7 +10,7 @@ topologicpy/DGL.py,sha256=Dd6O08D-vSxpjHYgKm45JpKiaeGvWlg1BRMzYMAXGNc,138991
|
|
10
10
|
topologicpy/Dictionary.py,sha256=cURg452wwk2WeSxWY46ncgAUo5XD1c2c5EtO6ESZHaY,27304
|
11
11
|
topologicpy/Edge.py,sha256=FACD8Bm2nL2uTHIeRMVXfRF0cYeqhZ-lCZPHAfjAIPg,66927
|
12
12
|
topologicpy/EnergyModel.py,sha256=NM3_nAdY9_YDtbp9CaEZ0x0xVsetTqVDzm_VSjmq_mI,53746
|
13
|
-
topologicpy/Face.py,sha256=
|
13
|
+
topologicpy/Face.py,sha256=emRTWbaLZeU3E0MprqpltTxC4ckv42h36enOcUMcLpU,124144
|
14
14
|
topologicpy/Graph.py,sha256=4b8bzlyXmh0Ef9rjiEjl8wmh_9vAxoE5xiSiGvGjG9Q,411392
|
15
15
|
topologicpy/Grid.py,sha256=3-sn7CHWGcXk18XCnHjsUttNJTWwmN63g_Insj__p04,18218
|
16
16
|
topologicpy/Helper.py,sha256=i-AfI29NMsZXBaymjilfvxQbuS3wpYbpPw4RWu1YCHs,16358
|
@@ -26,11 +26,11 @@ topologicpy/Sun.py,sha256=42tDWMYpwRG7Z2Qjtp94eRgBuqySq7k8TgNUZDK7QxQ,36837
|
|
26
26
|
topologicpy/Topology.py,sha256=DsRPV0iWUY2NIlxdvLLDBkkDY3xw8oYvmzQEEfJUusQ,398136
|
27
27
|
topologicpy/Vector.py,sha256=A1g83zDHep58iVPY8WQ8iHNrSOfGWFEzvVeDuMnjDNY,33078
|
28
28
|
topologicpy/Vertex.py,sha256=bLY60YWoMsgCgHk7F7k9F93Sq2FJ6AzUcTfJ83NZfHA,71107
|
29
|
-
topologicpy/Wire.py,sha256=
|
29
|
+
topologicpy/Wire.py,sha256=68KGFO6jere1aj5lci0W67kDRThXLMko8oY68q-ZP_A,171939
|
30
30
|
topologicpy/__init__.py,sha256=D7ky87CAQMiS2KE6YLvcTLkTgA2PY7rASe6Z23pjp9k,872
|
31
|
-
topologicpy/version.py,sha256=
|
32
|
-
topologicpy-0.7.
|
33
|
-
topologicpy-0.7.
|
34
|
-
topologicpy-0.7.
|
35
|
-
topologicpy-0.7.
|
36
|
-
topologicpy-0.7.
|
31
|
+
topologicpy/version.py,sha256=4-LUGtsfz8i419m9JYP1wXtHIMULgrganMwzGAvPIkU,23
|
32
|
+
topologicpy-0.7.65.dist-info/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
33
|
+
topologicpy-0.7.65.dist-info/METADATA,sha256=BzRukyNwXpaXv7OWSodC4FUsGbC5LMvLaGsAj10xvV8,10493
|
34
|
+
topologicpy-0.7.65.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
35
|
+
topologicpy-0.7.65.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
36
|
+
topologicpy-0.7.65.dist-info/RECORD,,
|
@@ -1,21 +0,0 @@
|
|
1
|
-
MIT License
|
2
|
-
|
3
|
-
Copyright (c) 2024 Wassim Jabi
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
13
|
-
copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
SOFTWARE.
|
File without changes
|
File without changes
|