Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/shapepy/analytic/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
from functools import lru_cache
from typing import Iterable, Set, Union

from rbool import SubSetR1, Whole, from_any

from ..rbool import SubSetR1, WholeR1, from_any
from ..scalar.reals import Real
from ..tools import Is

Expand Down Expand Up @@ -127,7 +126,7 @@ class BaseAnalytic(IAnalytic):
Base class parent of Analytic classes
"""

def __init__(self, coefs: Iterable[Real], domain: SubSetR1 = Whole()):
def __init__(self, coefs: Iterable[Real], domain: SubSetR1 = WholeR1()):
if not Is.iterable(coefs):
raise TypeError("Expected an iterable of coefficients")
coefs = tuple(coefs)
Expand Down Expand Up @@ -185,7 +184,7 @@ def __rmul__(self, other: Real) -> IAnalytic:
return self.__mul__(other)

def __repr__(self) -> str:
if self.domain is Whole():
if self.domain is WholeR1():
return str(self)
return f"{self.domain}: {self}"

Expand Down
5 changes: 2 additions & 3 deletions src/shapepy/analytic/bezier.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
from functools import lru_cache
from typing import Iterable, Tuple, Union

from rbool import SubSetR1, Whole

from ..loggers import debug
from ..rbool import SubSetR1, WholeR1
from ..scalar.quadrature import inner
from ..scalar.reals import Math, Rational, Real
from ..tools import Is, NotExpectedError, To
Expand Down Expand Up @@ -80,7 +79,7 @@ class Bezier(BaseAnalytic):
such as adding, subtracting, multiplying, etc
"""

def __init__(self, coefs: Iterable[Real], domain: SubSetR1 = Whole()):
def __init__(self, coefs: Iterable[Real], domain: SubSetR1 = WholeR1()):
super().__init__(coefs, domain)
self.__polynomial = bezier2polynomial(self)

Expand Down
5 changes: 2 additions & 3 deletions src/shapepy/analytic/polynomial.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
from numbers import Real
from typing import Iterable, List, Union

from rbool import move, scale

from ..loggers import debug
from ..rbool import scale, shift
from ..scalar.reals import Math
from ..tools import Is, To, vectorize
from .base import BaseAnalytic, IAnalytic
Expand Down Expand Up @@ -177,7 +176,7 @@ def shift(self, amount: Real) -> Polynomial:
if (i + j) % 2:
value *= -1
newcoefs[j] += coef * value
return Polynomial(newcoefs, move(self.domain, amount))
return Polynomial(newcoefs, shift(self.domain, amount))

@debug("shapepy.analytic.polynomial")
def integrate(self, times: int = 1) -> Polynomial:
Expand Down
40 changes: 22 additions & 18 deletions src/shapepy/analytic/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
from typing import Union

import numpy as np
from rbool import (
Empty,
SingleValue,

from ..loggers import debug
from ..rbool import (
EmptyR1,
SingleR1,
SubSetR1,
Whole,
WholeR1,
extract_knots,
from_any,
unite,
)

from ..loggers import debug
from ..scalar.reals import Math, Real
from ..tools import Is, NotExpectedError, To
from .base import IAnalytic, derivate_analytic
Expand All @@ -24,7 +24,7 @@


def find_polynomial_roots(
polynomial: Polynomial, domain: SubSetR1 = Whole()
polynomial: Polynomial, domain: SubSetR1 = WholeR1()
) -> SubSetR1:
"""
Finds all the values of t* such p(t*) = 0 inside given domain
Expand All @@ -33,15 +33,15 @@ def find_polynomial_roots(
polynomial = polynomial.clean()
domain &= polynomial.domain
if polynomial.degree == 0:
return domain if polynomial[0] == 0 else Empty()
return domain if polynomial[0] == 0 else EmptyR1()
if polynomial.degree == 1:
numerator = -To.rational(1, 1) * polynomial[0]
return SingleValue(numerator / polynomial[1])
return SingleR1(numerator / polynomial[1])
if polynomial.degree == 2:
c, b, a = polynomial
delta = b * b - 4 * a * c
if delta < 0:
return Empty()
return EmptyR1()
sqrtdelta = Math.sqrt(delta)
half = To.rational(1, 2)
x0 = half * (-b - sqrtdelta) / a
Expand All @@ -53,7 +53,7 @@ def find_polynomial_roots(


def where_minimum_polynomial(
polynomial: Polynomial, domain: SubSetR1 = Whole()
polynomial: Polynomial, domain: SubSetR1 = WholeR1()
) -> SubSetR1:
"""
Finds the value of t* such poly(t*) is minimal
Expand All @@ -62,8 +62,8 @@ def where_minimum_polynomial(
domain &= polynomial.domain
if polynomial.degree == 0:
return domain
if domain == Whole() and polynomial.degree % 2:
return Empty()
if domain == WholeR1() and polynomial.degree % 2:
return EmptyR1()
relation = {knot: polynomial(knot) for knot in extract_knots(domain)}
critical = find_roots(derivate_analytic(polynomial), domain)
for knot in extract_knots(critical):
Expand All @@ -78,7 +78,7 @@ def where_minimum_polynomial(


def find_minimum_polynomial(
polynomial: Polynomial, domain: SubSetR1 = Whole()
polynomial: Polynomial, domain: SubSetR1 = WholeR1()
) -> Union[Real, None]:
"""
Finds the minimal value of p(t) in the given domain
Expand All @@ -90,7 +90,7 @@ def find_minimum_polynomial(
assert Is.instance(polynomial, Polynomial)
if polynomial.degree == 0:
return polynomial[0]
if domain == Whole() and polynomial.degree % 2:
if domain == WholeR1() and polynomial.degree % 2:
return Math.NEGINF
relation = {}
relation = {knot: polynomial(knot) for knot in extract_knots(domain)}
Expand All @@ -103,7 +103,7 @@ def find_minimum_polynomial(


@debug("shapepy.analytic.tools")
def find_roots(analytic: IAnalytic, domain: SubSetR1 = Whole()) -> SubSetR1:
def find_roots(analytic: IAnalytic, domain: SubSetR1 = WholeR1()) -> SubSetR1:
"""
Finds the values of roots of the Analytic function
"""
Expand All @@ -117,7 +117,9 @@ def find_roots(analytic: IAnalytic, domain: SubSetR1 = Whole()) -> SubSetR1:


@debug("shapepy.analytic.tools")
def where_minimum(analytic: IAnalytic, domain: SubSetR1 = Whole()) -> SubSetR1:
def where_minimum(
analytic: IAnalytic, domain: SubSetR1 = WholeR1()
) -> SubSetR1:
"""
Finds the parameters (t*) such the analytic function is minimum
"""
Expand All @@ -131,7 +133,9 @@ def where_minimum(analytic: IAnalytic, domain: SubSetR1 = Whole()) -> SubSetR1:


@debug("shapepy.analytic.tools")
def find_minimum(analytic: IAnalytic, domain: SubSetR1 = Whole()) -> SubSetR1:
def find_minimum(
analytic: IAnalytic, domain: SubSetR1 = WholeR1()
) -> SubSetR1:
"""
Finds the minimal value for the given analytic in the given domain
"""
Expand Down
33 changes: 16 additions & 17 deletions src/shapepy/geometry/intersection.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@
from fractions import Fraction
from typing import Dict, Iterable, Set, Tuple, Union

from rbool import (
Empty,
Interval,
SingleValue,
from ..rbool import (
EmptyR1,
IntervalR1,
SingleR1,
SubSetR1,
extract_knots,
from_any,
)

from ..scalar.nodes_sample import NodeSampleFactory
from ..scalar.reals import Real
from ..tools import Is, NotExpectedError
Expand Down Expand Up @@ -150,7 +149,7 @@ def evaluate(self):
for curve in self.curves:
knots = curve.parametrize().knots
self.__all_knots[id(curve)] = set(knots)
self.__all_subsets[id(curve)] = Empty()
self.__all_subsets[id(curve)] = EmptyR1()
for i, j in self.pairs:
self.__evaluate_two(self.curves[i], self.curves[j])

Expand All @@ -159,7 +158,7 @@ def __evaluate_two(self, curvea: IGeometricCurve, curveb: IGeometricCurve):
Private function two compute the intersection between two curves
"""
subseta, subsetb = self.__compute_two(curvea, curveb)
if Is.instance(subseta, Empty):
if Is.instance(subseta, EmptyR1):
return
self.all_subsets[id(curvea)] |= subseta
self.all_knots[id(curvea)] |= set(extract_knots(subseta))
Expand All @@ -170,10 +169,10 @@ def __compute_two(
self, curvea: IGeometricCurve, curveb: IGeometricCurve
) -> Tuple[SubSetR1, SubSetR1]:
if curvea.box() & curveb.box() is None:
return Empty(), Empty()
return EmptyR1(), EmptyR1()
if id(curvea) == id(curveb): # Check if curves are equal
curvea = curvea.parametrize()
subset = Interval(curvea.knots[0], curvea.knots[-1])
subset = IntervalR1(curvea.knots[0], curvea.knots[-1])
return subset, subset
return curve_and_curve(curvea, curveb)

Expand All @@ -191,7 +190,7 @@ def __or__(
return GeometricIntersectionCurves(newcurves, newparis)

def __bool__(self):
return all(v == Empty() for v in self.all_subsets.values())
return all(v == EmptyR1() for v in self.all_subsets.values())


def curve_and_curve(
Expand Down Expand Up @@ -226,9 +225,9 @@ def segment_and_segment(
assert Is.instance(curvea, Segment)
assert Is.instance(curveb, Segment)
if curvea.box() & curveb.box() is None:
return Empty(), Empty()
return EmptyR1(), EmptyR1()
if curvea == curveb:
return Interval(0, 1), Interval(0, 1)
return IntervalR1(0, 1), IntervalR1(0, 1)
if segment_is_linear(curvea) and segment_is_linear(curveb):
return IntersectionSegments.lines(curvea, curveb)
nptsa = max(curvea.xfunc.degree, curvea.yfunc.degree) + 4
Expand Down Expand Up @@ -270,7 +269,7 @@ class IntersectionSegments:
@staticmethod
def lines(curvea: Segment, curveb: Segment) -> Tuple[SubSetR1, SubSetR1]:
"""Finds the intersection of two line segments"""
empty = Empty()
empty = EmptyR1()
A0, A1 = curvea(0), curvea(1)
B0, B1 = curveb(0), curveb(1)
dA = A1 - A0
Expand All @@ -284,7 +283,7 @@ def lines(curvea: Segment, curveb: Segment) -> Tuple[SubSetR1, SubSetR1]:
u0 = cross(B0mA0, dA) / dAxdB
if u0 < 0 or 1 < u0:
return empty, empty
return SingleValue(t0), SingleValue(u0)
return SingleR1(t0), SingleR1(u0)
# Lines are parallel
if cross(dA, B0mA0) != 0:
return empty, empty # Parallel, but not colinear
Expand All @@ -307,8 +306,8 @@ def lines(curvea: Segment, curveb: Segment) -> Tuple[SubSetR1, SubSetR1]:
u0 = min(max(0, u0), 1)
u1 = min(max(0, u1), 1)
if t0 == t1 or u0 == u1:
return SingleValue(t0), SingleValue(u1)
return Interval(t0, t1), Interval(u0, u1)
return SingleR1(t0), SingleR1(u1)
return IntervalR1(t0, t1), IntervalR1(u0, u1)

# pylint: disable=too-many-locals
@staticmethod
Expand Down Expand Up @@ -469,7 +468,7 @@ def intersect_piecewises(
assert Is.piecewise(curvea)
assert Is.piecewise(curveb)

subseta, subsetb = Empty(), Empty()
subseta, subsetb = EmptyR1(), EmptyR1()
for ai, sbezier in enumerate(curvea):
for bj, obezier in enumerate(curveb):
suba, subb = segment_and_segment(sbezier, obezier)
Expand Down
7 changes: 3 additions & 4 deletions src/shapepy/geometry/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
from copy import copy
from typing import Iterable, Optional, Tuple, Union

from rbool import Interval, from_any

from ..analytic.base import IAnalytic
from ..analytic.tools import find_minimum
from ..loggers import debug
from ..rbool import IntervalR1, from_any
from ..scalar.angle import Angle
from ..scalar.quadrature import AdaptativeIntegrator, IntegratorFactory
from ..scalar.reals import Math, Real
Expand Down Expand Up @@ -152,10 +151,10 @@ def split(self, nodes: Iterable[Real]) -> Tuple[Segment, ...]:
nodes = sorted(set(nodes) | set(self.knots))
return tuple(self.extract([ka, kb]) for ka, kb in pairs(nodes))

def extract(self, interval: Interval) -> Segment:
def extract(self, interval: IntervalR1) -> Segment:
"""Extracts a subsegment from the given segment"""
interval = from_any(interval)
if not Is.instance(interval, Interval):
if not Is.instance(interval, IntervalR1):
raise TypeError
knota, knotb = interval[0], interval[1]
denom = 1 / (knotb - knota)
Expand Down
16 changes: 16 additions & 0 deletions src/shapepy/rbool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Wraps the rbool library and add some useful functions for this package"""

from typing import Any, Callable, Iterator, Type

import rbool

EmptyR1: Type = rbool.Empty
IntervalR1: Type = rbool.Interval
SingleR1: Type = rbool.SingleValue
SubSetR1: Type = rbool.SubSetR1
WholeR1: Type = rbool.Whole
extract_knots: Callable[[Any], Iterator[Any]] = rbool.extract_knots
from_any: Callable[[Any], object] = rbool.from_any
shift = rbool.move
scale = rbool.scale
unite = rbool.unite
5 changes: 1 addition & 4 deletions tests/analytic/test_bezier.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
from fractions import Fraction as frac

import numpy as np
import pytest
from rbool import Interval

from shapepy.analytic.bezier import (
Bezier,
Expand Down Expand Up @@ -73,7 +70,7 @@ def test_matrices():
@pytest.mark.order(4)
@pytest.mark.dependency(depends=["test_build", "test_degree", "test_matrices"])
def test_compare():
domain = Interval(0, 1)
domain = [0, 1]
bezier = Bezier([1], domain)
assert bezier == Polynomial([1], domain)
assert bezier == 1
Expand Down
Loading
Loading