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 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.63'
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.63
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: MIT License
6
+ License: AGPL v3 License
7
7
 
8
8
  Copyright (c) 2024 Wassim Jabi
9
9
 
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
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
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
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
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
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=OyzEWdXl8yScHlyG3jDqcI31d_QlAt3SDma8AtkLQFs,116746
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=x2ut3Pej3fTBv1nPzQMsJ8asWFy4WKIjrAUPA0boesU,171628
29
+ topologicpy/Wire.py,sha256=68KGFO6jere1aj5lci0W67kDRThXLMko8oY68q-ZP_A,171939
30
30
  topologicpy/__init__.py,sha256=D7ky87CAQMiS2KE6YLvcTLkTgA2PY7rASe6Z23pjp9k,872
31
- topologicpy/version.py,sha256=MZJ0DcglO3LqgTS4xIW_NWvmDzvvzxd1VdjKOHudVIk,23
32
- topologicpy-0.7.63.dist-info/LICENSE,sha256=BRNw73R2WdDBICtwhI3wm3cxsaVqLTAGuRwrTltcfxs,1068
33
- topologicpy-0.7.63.dist-info/METADATA,sha256=EsGaYJ2wOBoqKTUUzAmNE_G0taxa5TW-Eg7UJzZqyYs,10920
34
- topologicpy-0.7.63.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
35
- topologicpy-0.7.63.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
36
- topologicpy-0.7.63.dist-info/RECORD,,
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.