<gh_stars>10-100
#! python
# -*- coding: utf-8 -*-
# (c) 2010 <NAME> LGPL

__author__ = "<NAME> <wmayer[at]users.sourceforge.net>"

# Formulas:
# M2 = P + b*r2 + t*u
# S1 = (r2*M1 + r1*M2)/(r1+r2)
# S2 = M2-b*r2

import math

# 3d vector class
class Vector:
	def __init__(self,x,y,z):
		self.x=x
		self.y=y
		self.z=z
	def add(self,vec):
		return Vector(self.x+vec.x,self.y+vec.y,self.z+vec.z)
	def sub(self,vec):
		return Vector(self.x-vec.x,self.y-vec.y,self.z-vec.z)
	def dot(self,vec):
		return self.x*vec.x+self.y*vec.y+self.z*vec.z
	def mult(self,s):
		return Vector(self.x*s,self.y*s,self.z*s)
	def cross(self,vec):
		return Vector(
		self.y * vec.z - self.z * vec.y,
		self.z * vec.x - self.x * vec.z,
		self.x * vec.y - self.y * vec.x)
	def length(self):
		return math.sqrt(self.x*self.x+self.y*self.y+self.z*self.z)
	def norm(self):
		l = self.length()
		if l > 0:
			self.x /= l
			self.y /= l
			self.z /= l
	def __repr__(self):
		return "(%f,%f,%f)" % (self.x,self.y,self.z)

# A signum function
def sgn(val):
	if val > 0:
		return 1
	elif val < 0:
		return -1
	else:
		return 0

# M1  ... is the center of the arc
# P   ... is the end point of the arc and start point of the line
# Q   ..  is a second point on the line
# N   ... is the normal of the plane where the arc and the line lie on, usually N=(0,0,1) 
# r2  ... the fillet radius
# ccw ... counter-clockwise means which part of the arc is given. ccw must be either True or False 
def makeFilletArc(M1,P,Q,N,r2,ccw):
	u = Q.sub(P)
	v = P.sub(M1)
	if ccw:
		b = u.cross(N)
	else:
		b = N.cross(u)
	b.norm()
	
	uu = u.dot(u)
	uv = u.dot(v)
	r1 = v.length()

	# distinguish between internal and external fillets
	r2 *= sgn(uv);

	cc = 2.0 * r2 * (b.dot(v)-r1)
	dd = uv * uv - uu * cc
	if dd < 0:
		raise RuntimeError("Unable to calculate intersection points")
	t1 = (-uv + math.sqrt(dd)) / uu 
	t2 = (-uv - math.sqrt(dd)) / uu
	
	if (abs(t1) < abs(t2)):
		t = t1
	else:
		t = t2
		
	br2 = b.mult(r2)
	print(br2)
	ut = u.mult(t)
	print(ut)
	M2 = P.add(ut).add(br2)
	S1 = M1.mult(r2/(r1+r2)).add(M2.mult(r1/(r1+r2)))
	S2 = M2.sub(br2)
	
	return (S1,S2,M2)

	
	
def test():
	from FreeCAD import Base
	import Part

	P1=Base.Vector(1,-5,0)
	P2=Base.Vector(-5,2,0)
	P3=Base.Vector(1,5,0)
	#Q=Base.Vector(5,10,0)
	#Q=Base.Vector(5,11,0)
	Q=Base.Vector(5,0,0)
	r2=3.0
	axis=Base.Vector(0,0,1)
	ccw=False

	arc=Part.ArcOfCircle(P1,P2,P3)
	C=arc.Center
	Part.show(Part.makeLine(P3,Q))
	Part.show(arc.toShape())

	(S1,S2,M2) = makeArc(Vector(C.x,C.y,C.z),Vector(P3.x,P3.y,P3.z),Vector(Q.x,Q.y,Q.z),Vector(axis.x,axis.y,axis.z),r2,ccw)
	circle=Part.Circle(Base.Vector(M2.x,M2.y,M2.z), Base.Vector(0,0,1), math.fabs(r2))
	Part.show(circle.toShape())

#! python
# -*- coding: utf-8 -*-
# (c) 2010 <NAME> LGPL

__author__ = "<NAME> <wmayer[at]users.sourceforge.net>"

# Formulas:
# M2 = P + b*r2 + t*u
# S1 = (r2*M1 + r1*M2)/(r1+r2)
# S2 = M2-b*r2

import math

# 3d vector class
class Vector:
	def __init__(self,x,y,z):
		self.x=x
		self.y=y
		self.z=z
	def add(self,vec):
		return Vector(self.x+vec.x,self.y+vec.y,self.z+vec.z)
	def sub(self,vec):
		return Vector(self.x-vec.x,self.y-vec.y,self.z-vec.z)
	def dot(self,vec):
		return self.x*vec.x+self.y*vec.y+self.z*vec.z
	def mult(self,s):
		return Vector(self.x*s,self.y*s,self.z*s)
	def cross(self,vec):
		return Vector(
		self.y * vec.z - self.z * vec.y,
		self.z * vec.x - self.x * vec.z,
		self.x * vec.y - self.y * vec.x)
	def length(self):
		return math.sqrt(self.x*self.x+self.y*self.y+self.z*self.z)
	def norm(self):
		l = self.length()
		if l > 0:
			self.x /= l
			self.y /= l
			self.z /= l
	def __repr__(self):
		return "(%f,%f,%f)" % (self.x,self.y,self.z)

# A signum function
def sgn(val):
	if val > 0:
		return 1
	elif val < 0:
		return -1
	else:
		return 0

# M1  ... is the center of the arc
# P   ... is the end point of the arc and start point of the line
# Q   ..  is a second point on the line
# N   ... is the normal of the plane where the arc and the line lie on, usually N=(0,0,1) 
# r2  ... the fillet radius
# ccw ... counter-clockwise means which part of the arc is given. ccw must be either True or False 
def makeFilletArc(M1,P,Q,N,r2,ccw):
	u = Q.sub(P)
	v = P.sub(M1)
	if ccw:
		b = u.cross(N)
	else:
		b = N.cross(u)
	b.norm()
	
	uu = u.dot(u)
	uv = u.dot(v)
	r1 = v.length()

	# distinguish between internal and external fillets
	r2 *= sgn(uv);

	cc = 2.0 * r2 * (b.dot(v)-r1)
	dd = uv * uv - uu * cc
	if dd < 0:
		raise RuntimeError("Unable to calculate intersection points")
	t1 = (-uv + math.sqrt(dd)) / uu 
	t2 = (-uv - math.sqrt(dd)) / uu
	
	if (abs(t1) < abs(t2)):
		t = t1
	else:
		t = t2
		
	br2 = b.mult(r2)
	print(br2)
	ut = u.mult(t)
	print(ut)
	M2 = P.add(ut).add(br2)
	S1 = M1.mult(r2/(r1+r2)).add(M2.mult(r1/(r1+r2)))
	S2 = M2.sub(br2)
	
	return (S1,S2,M2)

	
	
def test():
	from FreeCAD import Base
	import Part

	P1=Base.Vector(1,-5,0)
	P2=Base.Vector(-5,2,0)
	P3=Base.Vector(1,5,0)
	#Q=Base.Vector(5,10,0)
	#Q=Base.Vector(5,11,0)
	Q=Base.Vector(5,0,0)
	r2=3.0
	axis=Base.Vector(0,0,1)
	ccw=False

	arc=Part.ArcOfCircle(P1,P2,P3)
	C=arc.Center
	Part.show(Part.makeLine(P3,Q))
	Part.show(arc.toShape())

	(S1,S2,M2) = makeArc(Vector(C.x,C.y,C.z),Vector(P3.x,P3.y,P3.z),Vector(Q.x,Q.y,Q.z),Vector(axis.x,axis.y,axis.z),r2,ccw)
	circle=Part.Circle(Base.Vector(M2.x,M2.y,M2.z), Base.Vector(0,0,1), math.fabs(r2))
	Part.show(circle.toShape())
#! python # -*- coding: utf-8 -*- # (c) 2010 <NAME> LGPL # Formulas: # M2 = P + b*r2 + t*u # S1 = (r2*M1 + r1*M2)/(r1+r2) # S2 = M2-b*r2 # 3d vector class # A signum function # M1  ... is the center of the arc # P   ... is the end point of the arc and start point of the line # Q   ..  is a second point on the line # N   ... is the normal of the plane where the arc and the line lie on, usually N=(0,0,1) # r2  ... the fillet radius # ccw ... counter-clockwise means which part of the arc is given. ccw must be either True or False # distinguish between internal and external fillets #Q=Base.Vector(5,10,0) #Q=Base.Vector(5,11,0)