<commit_before>#include "CIntElement.hpp"
#include "CParticleGlobals.hpp"
#include "CRandom16.hpp"
#include "CElementGen.hpp"
#include "CGenDescription.hpp"

/* Documentation at: http://www.metroid2002.com/retromodding/wiki/Particle_Script#Int_Elements */

namespace urde {

CIEKeyframeEmitter::CIEKeyframeEmitter(CInputStream& in) {
  x4_percent = in.readUint32Big();
  x8_unk1 = in.readUint32Big();
  xc_loop = in.readBool();
  xd_unk2 = in.readBool();
  x10_loopEnd = in.readUint32Big();
  x14_loopStart = in.readUint32Big();

  u32 count = in.readUint32Big();
  x18_keys.reserve(count);
  for (u32 i = 0; i < count; ++i)
    x18_keys.push_back(in.readInt32Big());
}

bool CIEKeyframeEmitter::GetValue(int frame, int& valOut) const {
  if (!x4_percent) {
    int emitterTime = CParticleGlobals::g_EmitterTime;
    int calcKey = emitterTime;
    if (xc_loop) {
      if (emitterTime >= x10_loopEnd) {
        int v1 = emitterTime - x14_loopStart;
        int v2 = x10_loopEnd - x14_loopStart;
        calcKey = v1 % v2;
        calcKey += x14_loopStart;
      }
    } else {
      int v1 = x10_loopEnd - 1;
      if (v1 < emitterTime)
        calcKey = v1;
    }
    valOut = x18_keys[calcKey];
  } else {
    int ltPerc = CParticleGlobals::g_ParticleLifetimePercentage;
    float ltPercRem = CParticleGlobals::g_ParticleLifetimePercentageRemainder;
    if (ltPerc == 100)
      valOut = x18_keys[100];
    else
      valOut = ltPercRem * x18_keys[ltPerc + 1] + (1.0f - ltPercRem) * x18_keys[ltPerc];
  }
  return false;
}

int CIEKeyframeEmitter::GetMaxValue() const {
  int maxVal = INT_MIN;
  for (int k : x18_keys)
    if (k > maxVal)
      maxVal = k;
  return maxVal;
}

bool CIEDeath::GetValue(int frame, int& valOut) const {
  x4_a->GetValue(frame, valOut);
  int b;
  x8_b->GetValue(frame, b);
  /* Not 100% sure about this, originally some kinda branchless comparison */
  return frame > b;
}

int CIEDeath::GetMaxValue() const { return x4_a->GetMaxValue(); }

bool CIEClamp::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_min->GetValue(frame, a);
  x8_max->GetValue(frame, b);
  xc_val->GetValue(frame, valOut);
  if (valOut > b)
    valOut = b;
  if (valOut < a)
    valOut = a;
  return false;
}

int CIEClamp::GetMaxValue() const {
  const int a = x4_min->GetMaxValue();
  const int b = x8_max->GetMaxValue();
  int valOut = xc_val->GetMaxValue();

  if (valOut > b) {
    valOut = b;
  }
  if (valOut < a) {
    valOut = a;
  }

  return valOut;
}

bool CIETimeChain::GetValue(int frame, int& valOut) const {
  int v;
  xc_swFrame->GetValue(frame, v);
  if (frame >= v)
    return x8_b->GetValue(frame, valOut);
  else
    return x4_a->GetValue(frame, valOut);
}

int CIETimeChain::GetMaxValue() const { return std::max(x8_b->GetMaxValue(), x4_a->GetMaxValue()); }

bool CIEAdd::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_a->GetValue(frame, a);
  x8_b->GetValue(frame, b);
  valOut = a + b;
  return false;
}

int CIEAdd::GetMaxValue() const {
  const int a = x4_a->GetMaxValue();
  const int b = x8_b->GetMaxValue();
  return a + b;
}

bool CIEConstant::GetValue(int frame, int& valOut) const {
  valOut = x4_val;
  return false;
}

int CIEConstant::GetMaxValue() const { return x4_val; }

bool CIEImpulse::GetValue(int frame, int& valOut) const {
  if (frame == 0)
    x4_a->GetValue(frame, valOut);
  else
    valOut = 0;
  return false;
}

int CIEImpulse::GetMaxValue() const { return x4_a->GetMaxValue(); }

bool CIELifetimePercent::GetValue(int frame, int& valOut) const {
  int a;
  x4_percentVal->GetValue(frame, a);
  a = std::max(0, a);
  valOut = (a / 100.0f) * CParticleGlobals::g_ParticleLifetimeReal + 0.5f;
  return false;
}

int CIELifetimePercent::GetMaxValue() const {
  const int a = std::max(0, x4_percentVal->GetMaxValue());

  // Assume 10000 frames max (not ideal estimate)
  return int((float(a) / 100.0f) * 10000 + 0.5f);
}

bool CIEInitialRandom::GetValue(int frame, int& valOut) const {
  if (frame == 0) {
    int a, b;
    x4_a->GetValue(frame, a);
    x8_b->GetValue(frame, b);
    valOut = CRandom16::GetRandomNumber()->Range(a, b);
  }
  return false;
}

int CIEInitialRandom::GetMaxValue() const { return x8_b->GetMaxValue(); }

bool CIEPulse::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_aDuration->GetValue(frame, a);
  x8_bDuration->GetValue(frame, b);
  int cv = std::max(1, a + b + 1);

  if (b >= 1) {
    int cv2 = frame % cv;
    if (cv2 >= a)
      x10_bVal->GetValue(frame, valOut);
    else
      xc_aVal->GetValue(frame, valOut);
  } else
    xc_aVal->GetValue(frame, valOut);

  return false;
}

int CIEPulse::GetMaxValue() const { return std::max(xc_aVal->GetMaxValue(), x10_bVal->GetMaxValue()); }

bool CIEMultiply::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_a->GetValue(frame, a);
  x8_b->GetValue(frame, b);
  valOut = a * b;
  return false;
}

int CIEMultiply::GetMaxValue() const { return x4_a->GetMaxValue() * x8_b->GetMaxValue(); }

bool CIESampleAndHold::GetValue(int frame, int& valOut) const {
  if (x8_nextSampleFrame < frame) {
    int b, c;
    xc_waitFramesMin->GetValue(frame, b);
    x10_waitFramesMax->GetValue(frame, c);
    /* const-correctness, who needs it? */
    const_cast<CIESampleAndHold*>(this)->x8_nextSampleFrame = CRandom16::GetRandomNumber()->Range(b, c) + frame;
    x4_sampleSource->GetValue(frame, valOut);
    const_cast<CIESampleAndHold*>(this)->x14_holdVal = valOut;
  } else
    valOut = x14_holdVal;
  return false;
}

int CIESampleAndHold::GetMaxValue() const { return x4_sampleSource->GetMaxValue(); }

bool CIERandom::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_min->GetValue(frame, a);
  x8_max->GetValue(frame, b);
  if (a > 0)
    valOut = CRandom16::GetRandomNumber()->Range(a, b);
  else
    valOut = CRandom16::GetRandomNumber()->Next();
  return false;
}

int CIERandom::GetMaxValue() const {
  if (x4_min->GetMaxValue() > 0)
    return x8_max->GetMaxValue();
  else
    return 65535;
}

bool CIETimeScale::GetValue(int frame, int& valOut) const {
  float a;
  x4_a->GetValue(frame, a);
  valOut = float(frame) * a;
  return false;
}

int CIETimeScale::GetMaxValue() const { return 10000; /* Assume 10000 frames max (not ideal estimate) */ }

bool CIEGetCumulativeParticleCount::GetValue(int frame, int& valOut) const {
  valOut = CParticleGlobals::g_currentParticleSystem->x4_system->GetCumulativeParticleCount();
  return false;
}

int CIEGetCumulativeParticleCount::GetMaxValue() const { return 256; }

bool CIEGetActiveParticleCount::GetValue(int frame, int& valOut) const {
  valOut = CParticleGlobals::g_currentParticleSystem->x4_system->GetParticleCount();
  return false;
}

int CIEGetActiveParticleCount::GetMaxValue() const { return 256; }

bool CIEGetEmitterTime::GetValue(int frame, int& valOut) const {
  valOut = CParticleGlobals::g_currentParticleSystem->x4_system->GetEmitterTime();
  return false;
}

int CIEGetEmitterTime::GetMaxValue() const { return 10000; /* Assume 10000 frames max (not ideal estimate) */ }

bool CIEModulo::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_a->GetValue(frame, a);
  x8_b->GetValue(frame, b);
  if (b != 0)
    valOut = a % b;
  else
    valOut = a;
  return false;
}

int CIEModulo::GetMaxValue() const {
  const int a = x4_a->GetMaxValue();
  const int b = x8_b->GetMaxValue();

  if (b != 0) {
    return b - 1;
  }

  return a;
}

bool CIESubtract::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_a->GetValue(frame, a);
  x8_b->GetValue(frame, b);
  valOut = a - b;
  return false;
}

int CIESubtract::GetMaxValue() const {
  const int a = x4_a->GetMaxValue();
  const int b = x8_b->GetMaxValue();
  return a - b;
}

} // namespace urde
<commit_msg>CIntElement: Organize cpp includes<commit_after>#include "Runtime/Particle/CIntElement.hpp"

#include "Runtime/CRandom16.hpp"
#include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/Particle/CGenDescription.hpp"
#include "Runtime/Particle/CParticleGlobals.hpp"

/* Documentation at: http://www.metroid2002.com/retromodding/wiki/Particle_Script#Int_Elements */

namespace urde {

CIEKeyframeEmitter::CIEKeyframeEmitter(CInputStream& in) {
  x4_percent = in.readUint32Big();
  x8_unk1 = in.readUint32Big();
  xc_loop = in.readBool();
  xd_unk2 = in.readBool();
  x10_loopEnd = in.readUint32Big();
  x14_loopStart = in.readUint32Big();

  u32 count = in.readUint32Big();
  x18_keys.reserve(count);
  for (u32 i = 0; i < count; ++i)
    x18_keys.push_back(in.readInt32Big());
}

bool CIEKeyframeEmitter::GetValue(int frame, int& valOut) const {
  if (!x4_percent) {
    int emitterTime = CParticleGlobals::g_EmitterTime;
    int calcKey = emitterTime;
    if (xc_loop) {
      if (emitterTime >= x10_loopEnd) {
        int v1 = emitterTime - x14_loopStart;
        int v2 = x10_loopEnd - x14_loopStart;
        calcKey = v1 % v2;
        calcKey += x14_loopStart;
      }
    } else {
      int v1 = x10_loopEnd - 1;
      if (v1 < emitterTime)
        calcKey = v1;
    }
    valOut = x18_keys[calcKey];
  } else {
    int ltPerc = CParticleGlobals::g_ParticleLifetimePercentage;
    float ltPercRem = CParticleGlobals::g_ParticleLifetimePercentageRemainder;
    if (ltPerc == 100)
      valOut = x18_keys[100];
    else
      valOut = ltPercRem * x18_keys[ltPerc + 1] + (1.0f - ltPercRem) * x18_keys[ltPerc];
  }
  return false;
}

int CIEKeyframeEmitter::GetMaxValue() const {
  int maxVal = INT_MIN;
  for (int k : x18_keys)
    if (k > maxVal)
      maxVal = k;
  return maxVal;
}

bool CIEDeath::GetValue(int frame, int& valOut) const {
  x4_a->GetValue(frame, valOut);
  int b;
  x8_b->GetValue(frame, b);
  /* Not 100% sure about this, originally some kinda branchless comparison */
  return frame > b;
}

int CIEDeath::GetMaxValue() const { return x4_a->GetMaxValue(); }

bool CIEClamp::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_min->GetValue(frame, a);
  x8_max->GetValue(frame, b);
  xc_val->GetValue(frame, valOut);
  if (valOut > b)
    valOut = b;
  if (valOut < a)
    valOut = a;
  return false;
}

int CIEClamp::GetMaxValue() const {
  const int a = x4_min->GetMaxValue();
  const int b = x8_max->GetMaxValue();
  int valOut = xc_val->GetMaxValue();

  if (valOut > b) {
    valOut = b;
  }
  if (valOut < a) {
    valOut = a;
  }

  return valOut;
}

bool CIETimeChain::GetValue(int frame, int& valOut) const {
  int v;
  xc_swFrame->GetValue(frame, v);
  if (frame >= v)
    return x8_b->GetValue(frame, valOut);
  else
    return x4_a->GetValue(frame, valOut);
}

int CIETimeChain::GetMaxValue() const { return std::max(x8_b->GetMaxValue(), x4_a->GetMaxValue()); }

bool CIEAdd::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_a->GetValue(frame, a);
  x8_b->GetValue(frame, b);
  valOut = a + b;
  return false;
}

int CIEAdd::GetMaxValue() const {
  const int a = x4_a->GetMaxValue();
  const int b = x8_b->GetMaxValue();
  return a + b;
}

bool CIEConstant::GetValue(int frame, int& valOut) const {
  valOut = x4_val;
  return false;
}

int CIEConstant::GetMaxValue() const { return x4_val; }

bool CIEImpulse::GetValue(int frame, int& valOut) const {
  if (frame == 0)
    x4_a->GetValue(frame, valOut);
  else
    valOut = 0;
  return false;
}

int CIEImpulse::GetMaxValue() const { return x4_a->GetMaxValue(); }

bool CIELifetimePercent::GetValue(int frame, int& valOut) const {
  int a;
  x4_percentVal->GetValue(frame, a);
  a = std::max(0, a);
  valOut = (a / 100.0f) * CParticleGlobals::g_ParticleLifetimeReal + 0.5f;
  return false;
}

int CIELifetimePercent::GetMaxValue() const {
  const int a = std::max(0, x4_percentVal->GetMaxValue());

  // Assume 10000 frames max (not ideal estimate)
  return int((float(a) / 100.0f) * 10000 + 0.5f);
}

bool CIEInitialRandom::GetValue(int frame, int& valOut) const {
  if (frame == 0) {
    int a, b;
    x4_a->GetValue(frame, a);
    x8_b->GetValue(frame, b);
    valOut = CRandom16::GetRandomNumber()->Range(a, b);
  }
  return false;
}

int CIEInitialRandom::GetMaxValue() const { return x8_b->GetMaxValue(); }

bool CIEPulse::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_aDuration->GetValue(frame, a);
  x8_bDuration->GetValue(frame, b);
  int cv = std::max(1, a + b + 1);

  if (b >= 1) {
    int cv2 = frame % cv;
    if (cv2 >= a)
      x10_bVal->GetValue(frame, valOut);
    else
      xc_aVal->GetValue(frame, valOut);
  } else
    xc_aVal->GetValue(frame, valOut);

  return false;
}

int CIEPulse::GetMaxValue() const { return std::max(xc_aVal->GetMaxValue(), x10_bVal->GetMaxValue()); }

bool CIEMultiply::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_a->GetValue(frame, a);
  x8_b->GetValue(frame, b);
  valOut = a * b;
  return false;
}

int CIEMultiply::GetMaxValue() const { return x4_a->GetMaxValue() * x8_b->GetMaxValue(); }

bool CIESampleAndHold::GetValue(int frame, int& valOut) const {
  if (x8_nextSampleFrame < frame) {
    int b, c;
    xc_waitFramesMin->GetValue(frame, b);
    x10_waitFramesMax->GetValue(frame, c);
    /* const-correctness, who needs it? */
    const_cast<CIESampleAndHold*>(this)->x8_nextSampleFrame = CRandom16::GetRandomNumber()->Range(b, c) + frame;
    x4_sampleSource->GetValue(frame, valOut);
    const_cast<CIESampleAndHold*>(this)->x14_holdVal = valOut;
  } else
    valOut = x14_holdVal;
  return false;
}

int CIESampleAndHold::GetMaxValue() const { return x4_sampleSource->GetMaxValue(); }

bool CIERandom::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_min->GetValue(frame, a);
  x8_max->GetValue(frame, b);
  if (a > 0)
    valOut = CRandom16::GetRandomNumber()->Range(a, b);
  else
    valOut = CRandom16::GetRandomNumber()->Next();
  return false;
}

int CIERandom::GetMaxValue() const {
  if (x4_min->GetMaxValue() > 0)
    return x8_max->GetMaxValue();
  else
    return 65535;
}

bool CIETimeScale::GetValue(int frame, int& valOut) const {
  float a;
  x4_a->GetValue(frame, a);
  valOut = float(frame) * a;
  return false;
}

int CIETimeScale::GetMaxValue() const { return 10000; /* Assume 10000 frames max (not ideal estimate) */ }

bool CIEGetCumulativeParticleCount::GetValue(int frame, int& valOut) const {
  valOut = CParticleGlobals::g_currentParticleSystem->x4_system->GetCumulativeParticleCount();
  return false;
}

int CIEGetCumulativeParticleCount::GetMaxValue() const { return 256; }

bool CIEGetActiveParticleCount::GetValue(int frame, int& valOut) const {
  valOut = CParticleGlobals::g_currentParticleSystem->x4_system->GetParticleCount();
  return false;
}

int CIEGetActiveParticleCount::GetMaxValue() const { return 256; }

bool CIEGetEmitterTime::GetValue(int frame, int& valOut) const {
  valOut = CParticleGlobals::g_currentParticleSystem->x4_system->GetEmitterTime();
  return false;
}

int CIEGetEmitterTime::GetMaxValue() const { return 10000; /* Assume 10000 frames max (not ideal estimate) */ }

bool CIEModulo::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_a->GetValue(frame, a);
  x8_b->GetValue(frame, b);
  if (b != 0)
    valOut = a % b;
  else
    valOut = a;
  return false;
}

int CIEModulo::GetMaxValue() const {
  const int a = x4_a->GetMaxValue();
  const int b = x8_b->GetMaxValue();

  if (b != 0) {
    return b - 1;
  }

  return a;
}

bool CIESubtract::GetValue(int frame, int& valOut) const {
  int a, b;
  x4_a->GetValue(frame, a);
  x8_b->GetValue(frame, b);
  valOut = a - b;
  return false;
}

int CIESubtract::GetMaxValue() const {
  const int a = x4_a->GetMaxValue();
  const int b = x8_b->GetMaxValue();
  return a - b;
}

} // namespace urde
<|endoftext|>


<commit_before>#include "LineManager.h"
#include "ofxNearestNeighbour.h"

void LineManager::setup(){

	startFrame.addListener(this, &LineManager::paramChangedInt);
	endFrame.addListener(this, &LineManager::paramChangedInt);

	startPointX.addListener(this, &LineManager::paramChanged);
	startPointY.addListener(this, &LineManager::paramChanged);
	startPointZ.addListener(this, &LineManager::paramChanged);

	extrudeAmount.addListener(this, &LineManager::paramChanged);
	arcRadius.addListener(this, &LineManager::paramChanged);
	arcAngle.addListener(this, &LineManager::paramChanged);

//	rotationAmount.addListener(this, &LineManager::paramChanged);
	resampleAmount.addListener(this, &LineManager::paramChanged);

	chaseDampen.addListener(this, &LineManager::paramChanged);
	maxNewAngle.addListener(this, &LineManager::paramChanged);

	aRadius.addListener(this, &LineManager::paramChanged);
	bRadius.addListener(this, &LineManager::paramChanged);

	numAttachPoints.addListener(this, &LineManager::paramChanged);;

}

void LineManager::update(int cf){

	curFrame = ofClamp(cf,0,numFrames-1);

	/*
	if(meshes.size() > 0){
		int curIndex = ofClamp(curFrame,0,meshes.size()-1);
		curMesh = meshes[curIndex];
		curHooks = hooksPerFrame[curIndex];
	}
	 */

	//after building the arc we run the nodes along it and collect their path
	//along with resampling and storing the mesh for each frame

	b.setParent(a);
	b.setOrientation(ofQuaternion());
	b.setPosition(0, aRadius, 0);

	c.setParent(b);
	c.setOrientation(ofQuaternion());
	c.setPosition(0, bRadius, 0);

	for(int h = 0; h < hooks.size(); h++){
		hooks[h].firstHook = true;
	}

	vector<ofVec3f> linePoints;
	vector<AttachPoint> hooksThisFrame;
	float twistPoint = 0;
	for(int i = 0; i < curFrame; i++){
		float percentAlongCurve = 1.0 * i / numFrames; //(endFrame - startFrame);

		//apply the transform to the base
		int index = percentAlongCurve * (numFrames-2);
		int nextIndex = index+1;
		a.setTransformMatrix(ptf.frameAt(index));

		ofNode next;
		next.setTransformMatrix(ptf.frameAt(nextIndex));
		ofVec3f lookDir = next.getPosition() - a.getPosition();

		//rotate it around a consistent angle
		//a.rotate(rotationAmount*percentAlongCurve * ofSignedNoise(i/50.0), lookDir);
		float thisTwistDampen = ofMap(a.getPosition().y, yParamGradient-10, yParamGradient+10, twistDampen*20, twistDampen, true);
		twistPoint += 1.0 / thisTwistDampen;
		a.rotate(360 * ofSignedNoise(twistPoint), lookDir);

		ofQuaternion angleBtoC, angleAdjust;
		ofVec3f curLook = b.getSideDir();
		ofVec3f targetLook = c.getPosition() - b.getPosition();

		float angleBetween = curLook.angle(targetLook);
		b.rotate(angleBetween * chaseDampen, 0, 0, 1);

		//angleBtoC.makeRotate(curLook, targetLook);
		//angleAdjust.slerp(chaseDampen, b.getOrientationQuat()*angleBtoC, b.getOrientationQuat());
		//b.setOrientation(b.getOrientationQuat() * angleAdjust);
//		if(angleBetween < 5){
		if(i == 0){
//			c.rotateAround(ofQuaternion(ofRandom(-maxNewAngle,maxNewAngle), ofVec3f(0,0,1)), b.getPosition());
			c.rotateAround(ofQuaternion(maxNewAngle, ofVec3f(0,0,1)), b.getPosition());
		}

		//make B chase C
		//		ofNode aT,bT,cT;
		//		aT.setTransformMatrix(a.getGlobalTransformMatrix());
		//		bT.setTransformMatrix(b.getGlobalTransformMatrix());
		//		cT.setTransformMatrix(c.getGlobalTransformMatrix());

		//capture the parented position of c into n and add it to the path
		ofNode n;
		n.setTransformMatrix(c.getGlobalTransformMatrix());

		//add it to the points, resample and reset the current line to the resampled line
		//this is how the line uncurls over time
		linePoints.push_back(n.getPosition());
		ofPolyline p;
		p.addVertices(linePoints);
		p = p.getResampledByCount(resampleAmount);
		linePoints = p.getVertices();

		if(computeAttachmentPoints){
			ofxNearestNeighbour3D nn;
			nn.buildIndex(linePoints);

			hooksThisFrame.clear();

			//calculate hooks with the current line
			for(int h = 0; h < hooks.size(); h++){

				if(hooks[h].startFrame < i){
					//first time we have seen this point lock it to the line
					if(hooks[h].firstHook){
						hooks[h].xform = n;
						hooks[h].firstHook = false;
					}
					else{
						//STICKY POINTS woohoo!!!
						//otherise move it to the closest point on the resampled line
						vector<size_t> closestIndeces;
						vector<float> distances;
						nn.findNClosestPoints(hooks[h].xform.getPosition(), 2, closestIndeces, distances);

						ofVec3f x0 = hooks[h].xform.getPosition();
						ofVec3f x1 = linePoints[closestIndeces[0]];
						ofVec3f x2 = linePoints[closestIndeces[1]];
						//formulate for the distnce from a point to a line segment
						//					d   =   (|(x_2-x_1)x(x_1-x_0)|)/(|x_2-x_1|)
						float d = (x2-x1).getCrossed(x1-hooks[h].xform.getPosition()).length() / (x2-x1).length();
						//solve the pythag formula to get the distance along the line from x1 towards x2
						float xn = sqrt((float)(x0 - x1).lengthSquared() - d*d);
						//that leg of the triangle goes from x1 to x2
//						hooks[h].xform.getPosition() = ;
						hooks[h].xform.setPosition(x1 + (x2-x1).normalize() * xn);
						hooks[h].xform.lookAt(x2);
					}
				}
				else{
					hooks[h].xform = ofNode(); //hide off screen
				}

				hooksThisFrame.push_back(hooks[h]);

			}
		}
	}

	ofVec3f offset = currentHeadNode.getPosition() - baseHeadNode.getPosition();
	ofQuaternion q;
	q.makeRotate(currentHeadNode.getLookAtDir(), baseHeadNode.getLookAtDir());

	ofMatrix4x4 headTransform;
//	headTransform.makeTranslationMatrix(offset);
	headTransform.makeIdentityMatrix();
	headTransform.translate(-currentHeadNode.getPosition());
	headTransform.rotate(q);
	headTransform.translate( currentHeadNode.getPosition());
	headTransform.translate( -offset );
	cout << "head offset is " << offset << endl;

	curCurve.clear();
	curCurve.addVertices(linePoints);
	curCurve = curCurve.getResampledByCount(finalResampleCount);
	curCurve = curCurve.getSmoothed(finalSmoothAmount);

//	ofPolyline temp;
//	//apply all these
//	for (int i = 0; i < curCurve.getVertices().size(); i++) {
//		temp.addVertex(headTransform.preMult(curCurve.getVertices()[i]) );
//	}
//	curCurve = temp;
//
//	for(int h = 0; h < hooksThisFrame.size(); h++){
//		hooksThisFrame[h].xform.setTransformMatrix(headTransform * hooksThisFrame[h].xform.getGlobalTransformMatrix());
//	}
//	curHooks = hooksThisFrame;

	//store the mesh
	ofMesh m;
	m.setMode(OF_PRIMITIVE_LINE_STRIP);
	m.addVertices(curCurve.getVertices());
	curMesh = m;

	//create attachment points for the little tools
	//calculate KDTree of this line
//	hooksPerFrame.push_back(hooksThisFrame);

}

void LineManager::draw(){
	curMesh.draw();
	for(int i = 0; i < curHooks.size(); i++){
		ofDrawSphere(curHooks[i].xform.getPosition(), 10);
	}
}

void LineManager::drawArc(){
	ofMesh m;
	m.addVertices( basePoints );
	m.setMode(OF_PRIMITIVE_LINE_STRIP);
	m.draw();

	ptf.debugDraw(10.0);
}

void LineManager::paramChanged(float& param){
	generateArc();
}

void LineManager::paramChangedInt(int& param){
	generateArc();
}

void LineManager::generateArc(){

	b.setParent(a);
	b.setOrientation(ofQuaternion());
	b.setPosition(0, aRadius, 0);

	c.setParent(b);
	c.setOrientation(ofQuaternion());
	c.setPosition(0, bRadius, 0);

	numFrames = endFrame-startFrame;

	basePoints.clear();
	ptf.clear();
	hooks.clear();

	//the basis of this is a simple arc with a Parallel Transport Frame
	//PTF allows us to have a consistent normal and tangent from the curve as well as a position
	ofVec3f startPoint(startPointX,startPointY,startPointZ);
	for(int i = 0; i < numFrames; i++){

		float percentDone = 1.0 * i / numFrames;
		float angle = percentDone * arcAngle;

		ofVec3f pos = startPoint + ofVec3f(0,-1,0).getRotated(angle, ofVec3f(0,0,1) ) * arcRadius;
		pos += ofVec3f(0,0, extrudeAmount * percentDone);

		ptf.addPoint(pos);

		basePoints.push_back( pos );
	}

	for(int i = 0; i < numAttachPoints; i++){
		AttachPoint hook;
		hook.startFrame = ofMap(i, 0, numAttachPoints, 0, numFrames);
		hook.percentOnCurve = 1.0 * i / numAttachPoints;
		hook.firstHook = true; //set the initial position, then stick to the line
		hooks.push_back(hook);
	}

}

<commit_msg>stopped shake<commit_after>#include "LineManager.h"
#include "ofxNearestNeighbour.h"

void LineManager::setup(){

	startFrame.addListener(this, &LineManager::paramChangedInt);
	endFrame.addListener(this, &LineManager::paramChangedInt);

	startPointX.addListener(this, &LineManager::paramChanged);
	startPointY.addListener(this, &LineManager::paramChanged);
	startPointZ.addListener(this, &LineManager::paramChanged);

	extrudeAmount.addListener(this, &LineManager::paramChanged);
	arcRadius.addListener(this, &LineManager::paramChanged);
	arcAngle.addListener(this, &LineManager::paramChanged);

//	rotationAmount.addListener(this, &LineManager::paramChanged);
	resampleAmount.addListener(this, &LineManager::paramChanged);

	chaseDampen.addListener(this, &LineManager::paramChanged);
	maxNewAngle.addListener(this, &LineManager::paramChanged);

	aRadius.addListener(this, &LineManager::paramChanged);
	bRadius.addListener(this, &LineManager::paramChanged);

	numAttachPoints.addListener(this, &LineManager::paramChanged);;

}

void LineManager::update(int cf){

	curFrame = ofClamp(cf,0,numFrames-1);

	/*
	if(meshes.size() > 0){
		int curIndex = ofClamp(curFrame,0,meshes.size()-1);
		curMesh = meshes[curIndex];
		curHooks = hooksPerFrame[curIndex];
	}
	 */

	//after building the arc we run the nodes along it and collect their path
	//along with resampling and storing the mesh for each frame

	b.setParent(a);
	b.setOrientation(ofQuaternion());
	b.setPosition(0, aRadius, 0);

	c.setParent(b);
	c.setOrientation(ofQuaternion());
	c.setPosition(0, bRadius, 0);

	for(int h = 0; h < hooks.size(); h++){
		hooks[h].firstHook = true;
	}

	vector<ofVec3f> linePoints;
	vector<AttachPoint> hooksThisFrame;
	float twistPoint = 0;
	for(int i = 0; i < curFrame; i++){
		float percentAlongCurve = 1.0 * i / numFrames; //(endFrame - startFrame);

		//apply the transform to the base
		int index = percentAlongCurve * (numFrames-2);
		int nextIndex = index+1;
		a.setTransformMatrix(ptf.frameAt(index));

		ofNode next;
		next.setTransformMatrix(ptf.frameAt(nextIndex));
		ofVec3f lookDir = next.getPosition() - a.getPosition();

		//rotate it around a consistent angle
		//a.rotate(rotationAmount*percentAlongCurve * ofSignedNoise(i/50.0), lookDir);
		float thisTwistDampen = ofMap(a.getPosition().y, yParamGradient-10, yParamGradient+10, twistDampen*20, twistDampen, true);
		twistPoint += 1.0 / thisTwistDampen;
		a.rotate(360 * ofSignedNoise(twistPoint), lookDir);

		ofQuaternion angleBtoC, angleAdjust;
		ofVec3f curLook = b.getSideDir();
		ofVec3f targetLook = c.getPosition() - b.getPosition();

		float angleBetween = curLook.angle(targetLook);
		b.rotate(angleBetween * chaseDampen, 0, 0, 1);

		//angleBtoC.makeRotate(curLook, targetLook);
		//angleAdjust.slerp(chaseDampen, b.getOrientationQuat()*angleBtoC, b.getOrientationQuat());
		//b.setOrientation(b.getOrientationQuat() * angleAdjust);
//		if(angleBetween < 5){
		if(i == 0){
//			c.rotateAround(ofQuaternion(ofRandom(-maxNewAngle,maxNewAngle), ofVec3f(0,0,1)), b.getPosition());
			c.rotateAround(ofQuaternion(maxNewAngle, ofVec3f(0,0,1)), b.getPosition());
		}

		//make B chase C
		//		ofNode aT,bT,cT;
		//		aT.setTransformMatrix(a.getGlobalTransformMatrix());
		//		bT.setTransformMatrix(b.getGlobalTransformMatrix());
		//		cT.setTransformMatrix(c.getGlobalTransformMatrix());

		//capture the parented position of c into n and add it to the path
		ofNode n;
		n.setTransformMatrix(c.getGlobalTransformMatrix());

		//add it to the points, resample and reset the current line to the resampled line
		//this is how the line uncurls over time
		linePoints.push_back(n.getPosition());
		ofPolyline p;
		p.addVertices(linePoints);
		p = p.getResampledByCount(resampleAmount);
		linePoints = p.getVertices();

		if(computeAttachmentPoints){
			ofxNearestNeighbour3D nn;
			nn.buildIndex(linePoints);

			hooksThisFrame.clear();

			//calculate hooks with the current line
			for(int h = 0; h < hooks.size(); h++){

				if(hooks[h].startFrame < i){
					//first time we have seen this point lock it to the line
					if(hooks[h].firstHook){
						hooks[h].xform = n;
						hooks[h].firstHook = false;
					}
					else{
						//STICKY POINTS woohoo!!!
						//otherise move it to the closest point on the resampled line
						vector<size_t> closestIndeces;
						vector<float> distances;
						nn.findNClosestPoints(hooks[h].xform.getPosition(), 2, closestIndeces, distances);

						ofVec3f x0 = hooks[h].xform.getPosition();
						ofVec3f x1 = linePoints[closestIndeces[0]];
						ofVec3f x2 = linePoints[closestIndeces[1]];
						//formulate for the distnce from a point to a line segment
						//					d   =   (|(x_2-x_1)x(x_1-x_0)|)/(|x_2-x_1|)
						float d = (x2-x1).getCrossed(x1-hooks[h].xform.getPosition()).length() / (x2-x1).length();
						//solve the pythag formula to get the distance along the line from x1 towards x2
						float xn = sqrt((float)(x0 - x1).lengthSquared() - d*d);
						//that leg of the triangle goes from x1 to x2
//						hooks[h].xform.getPosition() = ;
						hooks[h].xform.setPosition(x1 + (x2-x1).normalize() * xn);
//						hooks[h].xform.lookAt(x2);
					}
				}
				else{
					hooks[h].xform = ofNode(); //hide off screen
				}

				hooksThisFrame.push_back(hooks[h]);

			}
		}
	}

	ofVec3f offset = currentHeadNode.getPosition() - baseHeadNode.getPosition();
	ofQuaternion q;
	q.makeRotate(currentHeadNode.getLookAtDir(), baseHeadNode.getLookAtDir());

	ofMatrix4x4 headTransform;
//	headTransform.makeTranslationMatrix(offset);
	headTransform.makeIdentityMatrix();
	headTransform.translate(-currentHeadNode.getPosition());
	headTransform.rotate(q);
	headTransform.translate( currentHeadNode.getPosition());
	headTransform.translate( -offset );
	cout << "head offset is " << offset << endl;

	curCurve.clear();
	curCurve.addVertices(linePoints);
	curCurve = curCurve.getResampledByCount(finalResampleCount);
	curCurve = curCurve.getSmoothed(finalSmoothAmount);

//	ofPolyline temp;
//	//apply all these
//	for (int i = 0; i < curCurve.getVertices().size(); i++) {
//		temp.addVertex(headTransform.preMult(curCurve.getVertices()[i]) );
//	}
//	curCurve = temp;
//
//	for(int h = 0; h < hooksThisFrame.size(); h++){
//		hooksThisFrame[h].xform.setTransformMatrix(headTransform * hooksThisFrame[h].xform.getGlobalTransformMatrix());
//	}
//	curHooks = hooksThisFrame;

	//store the mesh
	ofMesh m;
	m.setMode(OF_PRIMITIVE_LINE_STRIP);
	m.addVertices(curCurve.getVertices());
	curMesh = m;

	//create attachment points for the little tools
	//calculate KDTree of this line
//	hooksPerFrame.push_back(hooksThisFrame);

}

void LineManager::draw(){
	curMesh.draw();
	for(int i = 0; i < curHooks.size(); i++){
		ofDrawSphere(curHooks[i].xform.getPosition(), 10);
	}
}

void LineManager::drawArc(){
	ofMesh m;
	m.addVertices( basePoints );
	m.setMode(OF_PRIMITIVE_LINE_STRIP);
	m.draw();

	ptf.debugDraw(10.0);
}

void LineManager::paramChanged(float& param){
	generateArc();
}

void LineManager::paramChangedInt(int& param){
	generateArc();
}

void LineManager::generateArc(){

	b.setParent(a);
	b.setOrientation(ofQuaternion());
	b.setPosition(0, aRadius, 0);

	c.setParent(b);
	c.setOrientation(ofQuaternion());
	c.setPosition(0, bRadius, 0);

	numFrames = endFrame-startFrame;

	basePoints.clear();
	ptf.clear();
	hooks.clear();

	//the basis of this is a simple arc with a Parallel Transport Frame
	//PTF allows us to have a consistent normal and tangent from the curve as well as a position
	ofVec3f startPoint(startPointX,startPointY,startPointZ);
	for(int i = 0; i < numFrames; i++){

		float percentDone = 1.0 * i / numFrames;
		float angle = percentDone * arcAngle;

		ofVec3f pos = startPoint + ofVec3f(0,-1,0).getRotated(angle, ofVec3f(0,0,1) ) * arcRadius;
		pos += ofVec3f(0,0, extrudeAmount * percentDone);

		ptf.addPoint(pos);

		basePoints.push_back( pos );
	}

	for(int i = 0; i < numAttachPoints; i++){
		AttachPoint hook;
		hook.startFrame = ofMap(i, 0, numAttachPoints, 0, numFrames);
		hook.percentOnCurve = 1.0 * i / numAttachPoints;
		hook.firstHook = true; //set the initial position, then stick to the line
		hooks.push_back(hook);
	}

}

<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreMaya/FromMayaMeshConverter.h"
#include "IECoreMaya/FromMayaPlugConverter.h"
#include "IECoreMaya/MArrayIter.h"
#include "IECoreMaya/VectorTraits.h"

#include "IECore/MeshPrimitive.h"
#include "IECore/VectorOps.h"
#include "IECore/CompoundParameter.h"
#include "IECore/NumericParameter.h"
#include "IECore/MessageHandler.h"
#include "IECore/DespatchTypedData.h"
#include "IECore/ClassData.h"

#include "maya/MFn.h"
#include "maya/MFnMesh.h"
#include "maya/MFnAttribute.h"
#include "maya/MString.h"

#include <algorithm>

using namespace IECoreMaya;
using namespace IECore;
using namespace std;
using namespace Imath;

static const MFn::Type fromTypes[] = { MFn::kMesh, MFn::kMeshData, MFn::kInvalid };
static const IECore::TypeId toTypes[] = { BlindDataHolderTypeId, RenderableTypeId, VisibleRenderableTypeId, PrimitiveTypeId, MeshPrimitiveTypeId, InvalidTypeId };

FromMayaShapeConverter::Description<FromMayaMeshConverter> FromMayaMeshConverter::m_description( fromTypes, toTypes );

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// structors
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

FromMayaMeshConverter::FromMayaMeshConverter( const MObject &object )
	:	FromMayaShapeConverter( "FromMayaShapeConverter", "Converts poly meshes to IECore::MeshPrimitive objects.", object )
{
	constructCommon();
}

FromMayaMeshConverter::FromMayaMeshConverter( const MDagPath &dagPath )
	:	FromMayaShapeConverter( "FromMayaShapeConverter", "Converts poly meshes to IECore::MeshPrimitive objects.", dagPath )
{
	constructCommon();
}

void FromMayaMeshConverter::constructCommon()
{

	// interpolation
	StringParameter::PresetsMap interpolationPresets;
	interpolationPresets["poly"] = "linear";
	interpolationPresets["subdiv"] = "catmullClark";

	m_interpolation = new StringParameter(
		"interpolation",
		"Sets the interpolation type of the new mesh",
		"linear",
		interpolationPresets
	);

	parameters()->addParameter( m_interpolation );

	// points
	BoolParameter::PresetsMap pointsPresets;
	pointsPresets["poly"] = true;
	pointsPresets["subdiv"] = true;

	m_points = new BoolParameter(
		"points",
		"When this is on the mesh points are added to the result as a primitive variable named \"P\".",
		true,
		pointsPresets
	);

	parameters()->addParameter( m_points );

	// normals
	BoolParameter::PresetsMap normalsPresets;
	normalsPresets["poly"] = true;
	normalsPresets["subdiv"] = false;

	m_normals = new BoolParameter(
		"normals",
		"When this is on the mesh normals are added to the result as a primitive variable named \"N\". "
		"Note that normals will only ever be added to meshes created with linear interpolation as "
		"vertex normals are unsuitable for meshes which will be rendered with some form of "
		"subdivision.",
		true,
		normalsPresets
	);

	parameters()->addParameter( m_normals );

	// st
	BoolParameter::PresetsMap stPresets;
	stPresets["poly"] = true;
	stPresets["subdiv"] = true;

	m_st = new BoolParameter(
		"st",
		"When this is on the default uv set is added to the result as primitive variables named \"s\" and \"t\".",
		true,
		stPresets
	);

	parameters()->addParameter( m_st );

	// extra st
	BoolParameter::PresetsMap extraSTPresets;
	extraSTPresets["poly"] = true;
	extraSTPresets["subdiv"] = true;

	m_extraST = new BoolParameter(
		"extraST",
		"When this is on any additional uv sets are added to the result as primitive variables named \"setName_s\" and \"setName_t\".",
		true,
		extraSTPresets
	);

	parameters()->addParameter( m_extraST );

}

FromMayaMeshConverter::~FromMayaMeshConverter()
{
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameter access
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

IECore::StringParameterPtr FromMayaMeshConverter::interpolationParameter()
{
	return m_interpolation;
}

IECore::StringParameterPtr FromMayaMeshConverter::interpolationParameter() const
{
	return m_interpolation;
}

IECore::BoolParameterPtr FromMayaMeshConverter::pointsParameter()
{
	return m_points;
}

IECore::BoolParameterPtr FromMayaMeshConverter::pointsParameter() const
{
	return m_points;
}

IECore::BoolParameterPtr FromMayaMeshConverter::normalsParameter()
{
	return m_normals;
}

IECore::BoolParameterPtr FromMayaMeshConverter::normalsParameter() const
{
	return m_normals;
}

IECore::BoolParameterPtr FromMayaMeshConverter::stParameter()
{
	return m_st;
}

IECore::BoolParameterPtr FromMayaMeshConverter::stParameter() const
{
	return m_st;
}

IECore::BoolParameterPtr FromMayaMeshConverter::extraSTParameter()
{
	return m_extraST;
}

IECore::BoolParameterPtr FromMayaMeshConverter::extraSTParameter() const
{
	return m_extraST;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// conversion
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

IECore::V3fVectorDataPtr FromMayaMeshConverter::points() const
{
	MFnMesh fnMesh;
	const MDagPath *d = dagPath( true );
	if( d )
	{
		fnMesh.setObject( *d );
	}
	else
	{
		fnMesh.setObject( object() );
	}

	MFloatPointArray mPoints;
	fnMesh.getPoints( mPoints, space() );

	V3fVectorDataPtr points = new V3fVectorData;
	points->writable().resize( mPoints.length() );
	std::transform( MArrayIter<MFloatPointArray>::begin( mPoints ), MArrayIter<MFloatPointArray>::end( mPoints ), points->writable().begin(), VecConvert<MFloatPoint, V3f>() );
	return points;
}

IECore::V3fVectorDataPtr FromMayaMeshConverter::normals() const
{
	MFnMesh fnMesh;
	const MDagPath *d = dagPath( true );
	if( d )
	{
		fnMesh.setObject( *d );
	}
	else
	{
		fnMesh.setObject( object() );
	}

	V3fVectorDataPtr normalsData = new V3fVectorData;
	vector<V3f> &normals = normalsData->writable();
	normals.resize( fnMesh.numFaceVertices() );

	int numPolygons = fnMesh.numPolygons();
	MFloatVectorArray faceNormals;
	unsigned int normalIndex = 0;
	for( int i=0; i<numPolygons; i++ )
	{
		fnMesh.getFaceVertexNormals( i, faceNormals, space() );
		for( unsigned j=0; j<faceNormals.length(); j++ )
		{
			normals[normalIndex++] = vecConvert<MVector, V3f>( faceNormals[j] );
		}
	}
	assert( normalIndex==normals.size() );
	return normalsData;
}

IECore::FloatVectorDataPtr FromMayaMeshConverter::sOrT( const MString &uvSet, unsigned int index ) const
{
	MFnMesh fnMesh( object() );
	FloatVectorDataPtr resultData = new FloatVectorData;
	vector<float> &result = resultData->writable();
	result.resize( fnMesh.numFaceVertices() );
	int numPolygons = fnMesh.numPolygons();
	unsigned int resultIndex = 0;
	for( int i=0; i<numPolygons; i++ )
	{
		for( int j=0; j<fnMesh.polygonVertexCount( i ); j++ )
		{
			float uv[2];
			fnMesh.getPolygonUV( i, j, uv[0], uv[1], &uvSet );
			result[resultIndex++] = index==1 ? 1-uv[index] : uv[index];
		}
	}
	return resultData;

}

IECore::FloatVectorDataPtr FromMayaMeshConverter::s( const MString &uvSet ) const
{
	return sOrT( uvSet, 0 );
}

IECore::FloatVectorDataPtr FromMayaMeshConverter::t( const MString &uvSet ) const
{
	return sOrT( uvSet, 1 );
}

IECore::PrimitivePtr FromMayaMeshConverter::doPrimitiveConversion( const MObject &object, IECore::ConstCompoundObjectPtr operands ) const
{
	MFnMesh fnMesh( object );
	return doPrimitiveConversion( fnMesh );
}

IECore::PrimitivePtr FromMayaMeshConverter::doPrimitiveConversion( const MDagPath &dagPath, IECore::ConstCompoundObjectPtr operands ) const
{
	MFnMesh fnMesh( dagPath );
	return doPrimitiveConversion( fnMesh );
}

IECore::PrimitivePtr FromMayaMeshConverter::doPrimitiveConversion( MFnMesh &fnMesh ) const
{
	// get basic topology and create a mesh
	int numPolygons = fnMesh.numPolygons();
	IntVectorDataPtr verticesPerFaceData = new IntVectorData;
	verticesPerFaceData->writable().resize( numPolygons );
	vector<int>::iterator verticesPerFaceIt = verticesPerFaceData->writable().begin();

	IntVectorDataPtr vertexIds = new IntVectorData;
	vertexIds->writable().resize( fnMesh.numFaceVertices() );
	vector<int>::iterator vertexIdsIt = vertexIds->writable().begin();

	MIntArray polygonVertices;
	for( int i=0; i<numPolygons; i++ )
	{
		fnMesh.getPolygonVertices( i, polygonVertices );
		*verticesPerFaceIt++ = polygonVertices.length();
		copy( MArrayIter<MIntArray>::begin( polygonVertices ), MArrayIter<MIntArray>::end( polygonVertices ), vertexIdsIt );
		vertexIdsIt += polygonVertices.length();
	}

	/// \todo Allow construction of empty meshes. Currently this MeshPrimitive constructor throws if there are no polygons. So we either need to change
	/// that behaviour, or call the MeshPrimitive() constructor if there are no polygons.
	MeshPrimitivePtr result = new MeshPrimitive( verticesPerFaceData, vertexIds, m_interpolation->getTypedValue() );

	if( m_points->getTypedValue() )
	{
		result->variables["P"] = PrimitiveVariable( PrimitiveVariable::Vertex, points() );
	}
	if( m_normals->getTypedValue() && m_interpolation->getTypedValue()=="linear" )
	{
		result->variables["N"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, normals() );
	}

	MString currentUVSet;
	fnMesh.getCurrentUVSetName( currentUVSet );
	MStringArray uvSets;
	fnMesh.getUVSetNames( uvSets );
	for( unsigned int i=0; i<uvSets.length(); i++ )
	{
		FloatVectorDataPtr sData = s( uvSets[i] );
		FloatVectorDataPtr tData = t( uvSets[i] );
		if( uvSets[i]==currentUVSet )
		{
			if( m_st->getTypedValue() )
			{
				result->variables["s"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, sData );
				result->variables["t"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, tData );
			}
		}
		else
		{
			if( m_extraST->getTypedValue() )
			{
				MString sName = uvSets[i] + "_s";
				MString tName = uvSets[i] + "_t";
				result->variables[sName.asChar()] = PrimitiveVariable( PrimitiveVariable::FaceVarying, sData );
				result->variables[tName.asChar()] = PrimitiveVariable( PrimitiveVariable::FaceVarying, tData );
			}
		}
	}

	return result;
}
<commit_msg>Removed todo which was dealt with in the MeshPrimitive constructor.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreMaya/FromMayaMeshConverter.h"
#include "IECoreMaya/FromMayaPlugConverter.h"
#include "IECoreMaya/MArrayIter.h"
#include "IECoreMaya/VectorTraits.h"

#include "IECore/MeshPrimitive.h"
#include "IECore/VectorOps.h"
#include "IECore/CompoundParameter.h"
#include "IECore/NumericParameter.h"
#include "IECore/MessageHandler.h"
#include "IECore/DespatchTypedData.h"
#include "IECore/ClassData.h"

#include "maya/MFn.h"
#include "maya/MFnMesh.h"
#include "maya/MFnAttribute.h"
#include "maya/MString.h"

#include <algorithm>

using namespace IECoreMaya;
using namespace IECore;
using namespace std;
using namespace Imath;

static const MFn::Type fromTypes[] = { MFn::kMesh, MFn::kMeshData, MFn::kInvalid };
static const IECore::TypeId toTypes[] = { BlindDataHolderTypeId, RenderableTypeId, VisibleRenderableTypeId, PrimitiveTypeId, MeshPrimitiveTypeId, InvalidTypeId };

FromMayaShapeConverter::Description<FromMayaMeshConverter> FromMayaMeshConverter::m_description( fromTypes, toTypes );

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// structors
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

FromMayaMeshConverter::FromMayaMeshConverter( const MObject &object )
	:	FromMayaShapeConverter( "FromMayaShapeConverter", "Converts poly meshes to IECore::MeshPrimitive objects.", object )
{
	constructCommon();
}

FromMayaMeshConverter::FromMayaMeshConverter( const MDagPath &dagPath )
	:	FromMayaShapeConverter( "FromMayaShapeConverter", "Converts poly meshes to IECore::MeshPrimitive objects.", dagPath )
{
	constructCommon();
}

void FromMayaMeshConverter::constructCommon()
{

	// interpolation
	StringParameter::PresetsMap interpolationPresets;
	interpolationPresets["poly"] = "linear";
	interpolationPresets["subdiv"] = "catmullClark";

	m_interpolation = new StringParameter(
		"interpolation",
		"Sets the interpolation type of the new mesh",
		"linear",
		interpolationPresets
	);

	parameters()->addParameter( m_interpolation );

	// points
	BoolParameter::PresetsMap pointsPresets;
	pointsPresets["poly"] = true;
	pointsPresets["subdiv"] = true;

	m_points = new BoolParameter(
		"points",
		"When this is on the mesh points are added to the result as a primitive variable named \"P\".",
		true,
		pointsPresets
	);

	parameters()->addParameter( m_points );

	// normals
	BoolParameter::PresetsMap normalsPresets;
	normalsPresets["poly"] = true;
	normalsPresets["subdiv"] = false;

	m_normals = new BoolParameter(
		"normals",
		"When this is on the mesh normals are added to the result as a primitive variable named \"N\". "
		"Note that normals will only ever be added to meshes created with linear interpolation as "
		"vertex normals are unsuitable for meshes which will be rendered with some form of "
		"subdivision.",
		true,
		normalsPresets
	);

	parameters()->addParameter( m_normals );

	// st
	BoolParameter::PresetsMap stPresets;
	stPresets["poly"] = true;
	stPresets["subdiv"] = true;

	m_st = new BoolParameter(
		"st",
		"When this is on the default uv set is added to the result as primitive variables named \"s\" and \"t\".",
		true,
		stPresets
	);

	parameters()->addParameter( m_st );

	// extra st
	BoolParameter::PresetsMap extraSTPresets;
	extraSTPresets["poly"] = true;
	extraSTPresets["subdiv"] = true;

	m_extraST = new BoolParameter(
		"extraST",
		"When this is on any additional uv sets are added to the result as primitive variables named \"setName_s\" and \"setName_t\".",
		true,
		extraSTPresets
	);

	parameters()->addParameter( m_extraST );

}

FromMayaMeshConverter::~FromMayaMeshConverter()
{
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameter access
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

IECore::StringParameterPtr FromMayaMeshConverter::interpolationParameter()
{
	return m_interpolation;
}

IECore::StringParameterPtr FromMayaMeshConverter::interpolationParameter() const
{
	return m_interpolation;
}

IECore::BoolParameterPtr FromMayaMeshConverter::pointsParameter()
{
	return m_points;
}

IECore::BoolParameterPtr FromMayaMeshConverter::pointsParameter() const
{
	return m_points;
}

IECore::BoolParameterPtr FromMayaMeshConverter::normalsParameter()
{
	return m_normals;
}

IECore::BoolParameterPtr FromMayaMeshConverter::normalsParameter() const
{
	return m_normals;
}

IECore::BoolParameterPtr FromMayaMeshConverter::stParameter()
{
	return m_st;
}

IECore::BoolParameterPtr FromMayaMeshConverter::stParameter() const
{
	return m_st;
}

IECore::BoolParameterPtr FromMayaMeshConverter::extraSTParameter()
{
	return m_extraST;
}

IECore::BoolParameterPtr FromMayaMeshConverter::extraSTParameter() const
{
	return m_extraST;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// conversion
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

IECore::V3fVectorDataPtr FromMayaMeshConverter::points() const
{
	MFnMesh fnMesh;
	const MDagPath *d = dagPath( true );
	if( d )
	{
		fnMesh.setObject( *d );
	}
	else
	{
		fnMesh.setObject( object() );
	}

	MFloatPointArray mPoints;
	fnMesh.getPoints( mPoints, space() );

	V3fVectorDataPtr points = new V3fVectorData;
	points->writable().resize( mPoints.length() );
	std::transform( MArrayIter<MFloatPointArray>::begin( mPoints ), MArrayIter<MFloatPointArray>::end( mPoints ), points->writable().begin(), VecConvert<MFloatPoint, V3f>() );
	return points;
}

IECore::V3fVectorDataPtr FromMayaMeshConverter::normals() const
{
	MFnMesh fnMesh;
	const MDagPath *d = dagPath( true );
	if( d )
	{
		fnMesh.setObject( *d );
	}
	else
	{
		fnMesh.setObject( object() );
	}

	V3fVectorDataPtr normalsData = new V3fVectorData;
	vector<V3f> &normals = normalsData->writable();
	normals.resize( fnMesh.numFaceVertices() );

	int numPolygons = fnMesh.numPolygons();
	MFloatVectorArray faceNormals;
	unsigned int normalIndex = 0;
	for( int i=0; i<numPolygons; i++ )
	{
		fnMesh.getFaceVertexNormals( i, faceNormals, space() );
		for( unsigned j=0; j<faceNormals.length(); j++ )
		{
			normals[normalIndex++] = vecConvert<MVector, V3f>( faceNormals[j] );
		}
	}
	assert( normalIndex==normals.size() );
	return normalsData;
}

IECore::FloatVectorDataPtr FromMayaMeshConverter::sOrT( const MString &uvSet, unsigned int index ) const
{
	MFnMesh fnMesh( object() );
	FloatVectorDataPtr resultData = new FloatVectorData;
	vector<float> &result = resultData->writable();
	result.resize( fnMesh.numFaceVertices() );
	int numPolygons = fnMesh.numPolygons();
	unsigned int resultIndex = 0;
	for( int i=0; i<numPolygons; i++ )
	{
		for( int j=0; j<fnMesh.polygonVertexCount( i ); j++ )
		{
			float uv[2];
			fnMesh.getPolygonUV( i, j, uv[0], uv[1], &uvSet );
			result[resultIndex++] = index==1 ? 1-uv[index] : uv[index];
		}
	}
	return resultData;

}

IECore::FloatVectorDataPtr FromMayaMeshConverter::s( const MString &uvSet ) const
{
	return sOrT( uvSet, 0 );
}

IECore::FloatVectorDataPtr FromMayaMeshConverter::t( const MString &uvSet ) const
{
	return sOrT( uvSet, 1 );
}

IECore::PrimitivePtr FromMayaMeshConverter::doPrimitiveConversion( const MObject &object, IECore::ConstCompoundObjectPtr operands ) const
{
	MFnMesh fnMesh( object );
	return doPrimitiveConversion( fnMesh );
}

IECore::PrimitivePtr FromMayaMeshConverter::doPrimitiveConversion( const MDagPath &dagPath, IECore::ConstCompoundObjectPtr operands ) const
{
	MFnMesh fnMesh( dagPath );
	return doPrimitiveConversion( fnMesh );
}

IECore::PrimitivePtr FromMayaMeshConverter::doPrimitiveConversion( MFnMesh &fnMesh ) const
{
	// get basic topology and create a mesh
	int numPolygons = fnMesh.numPolygons();
	IntVectorDataPtr verticesPerFaceData = new IntVectorData;
	verticesPerFaceData->writable().resize( numPolygons );
	vector<int>::iterator verticesPerFaceIt = verticesPerFaceData->writable().begin();

	IntVectorDataPtr vertexIds = new IntVectorData;
	vertexIds->writable().resize( fnMesh.numFaceVertices() );
	vector<int>::iterator vertexIdsIt = vertexIds->writable().begin();

	MIntArray polygonVertices;
	for( int i=0; i<numPolygons; i++ )
	{
		fnMesh.getPolygonVertices( i, polygonVertices );
		*verticesPerFaceIt++ = polygonVertices.length();
		copy( MArrayIter<MIntArray>::begin( polygonVertices ), MArrayIter<MIntArray>::end( polygonVertices ), vertexIdsIt );
		vertexIdsIt += polygonVertices.length();
	}

	MeshPrimitivePtr result = new MeshPrimitive( verticesPerFaceData, vertexIds, m_interpolation->getTypedValue() );

	if( m_points->getTypedValue() )
	{
		result->variables["P"] = PrimitiveVariable( PrimitiveVariable::Vertex, points() );
	}
	if( m_normals->getTypedValue() && m_interpolation->getTypedValue()=="linear" )
	{
		result->variables["N"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, normals() );
	}

	MString currentUVSet;
	fnMesh.getCurrentUVSetName( currentUVSet );
	MStringArray uvSets;
	fnMesh.getUVSetNames( uvSets );
	for( unsigned int i=0; i<uvSets.length(); i++ )
	{
		FloatVectorDataPtr sData = s( uvSets[i] );
		FloatVectorDataPtr tData = t( uvSets[i] );
		if( uvSets[i]==currentUVSet )
		{
			if( m_st->getTypedValue() )
			{
				result->variables["s"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, sData );
				result->variables["t"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, tData );
			}
		}
		else
		{
			if( m_extraST->getTypedValue() )
			{
				MString sName = uvSets[i] + "_s";
				MString tName = uvSets[i] + "_t";
				result->variables[sName.asChar()] = PrimitiveVariable( PrimitiveVariable::FaceVarying, sData );
				result->variables[tName.asChar()] = PrimitiveVariable( PrimitiveVariable::FaceVarying, tData );
			}
		}
	}

	return result;
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2015 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <sstream>
#include <QtGui>
#include <Interface/Application/NetworkEditor.h>
#include <Interface/Application/Node.h>
#include <Interface/Application/Connection.h>
#include <Interface/Application/ModuleWidget.h>
#include <Interface/Application/ModuleProxyWidget.h>
#include <Interface/Application/PortWidgetManager.h>
#include <Interface/Application/NetworkEditorControllerGuiProxy.h>
#include <Interface/Application/Subnetworks.h>
#include <Dataflow/Serialization/Network/NetworkDescriptionSerialization.h>
#include <Dataflow/Engine/Controller/NetworkEditorController.h> //TODO: remove
#include <Dataflow/Network/Module.h> //TODO: remove
#include <Core/Application/Preferences/Preferences.h>
#include <Core/Application/Application.h>
#include <Dataflow/Serialization/Network/XMLSerializer.h>
#include <boost/lambda/lambda.hpp>

using namespace SCIRun;
using namespace SCIRun::Core;
using namespace SCIRun::Core::Algorithms;
using namespace SCIRun::Gui;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Dataflow::Engine;

NetworkEditor::~NetworkEditor()
{
  sendItemsToParent();

  for (auto& child : childrenNetworks_)
  {
    delete child.second->get();
    child.second = nullptr;
  }

  Q_FOREACH(QGraphicsItem* item, scene_->items())
  {
    auto module = getModule(item);
    if (module)
      module->setDeletedFromGui(false);
  }
  NetworkEditor::clear();
}

SubnetworkEditor::SubnetworkEditor(NetworkEditor* editor, const ModuleId& subnetModuleId, const QString& name, QWidget* parent) : QDockWidget(parent),
editor_(editor), name_(name), subnetModuleId_(subnetModuleId)
{
  setupUi(this);
  groupBox->setTitle(name);
  auto vbox = new QVBoxLayout;
  vbox->addWidget(editor);
  groupBox->setLayout(vbox);
  connect(expandPushButton_, SIGNAL(clicked()), this, SLOT(expand()));
}

void SubnetworkEditor::expand()
{
  editor_->sendItemsToParent();
  editor_->parentNetwork()->removeModuleWidget(subnetModuleId_);
  editor_->parentNetwork()->removeSubnetChild(name_);
  deleteLater();
}

void NetworkEditor::sendItemsToParent()
{
  if (parentNetwork_)
  {
    for (auto& item : scene_->items())
      parentNetwork_->scene_->addItem(item);
  }
}

void NetworkEditor::removeSubnetChild(const QString& name)
{
  childrenNetworks_.erase(name);
}

void NetworkEditor::addSubnetChild(const QString& name, const ModuleId& mid)
{
  auto it = childrenNetworks_.find(name);
  if (it == childrenNetworks_.end())
  {
    auto subnet = new NetworkEditor(ctorParams_);
    initializeSubnet(name, mid, subnet);
  }
  else
  {
    it->second->show();
  }
}

void NetworkEditor::showSubnetChild(const QString& name)
{
  auto it = childrenNetworks_.find(name);
  if (it == childrenNetworks_.end())
  {
    throw "logical error";
  }
  else
  {
    it->second->show();
  }
}

void NetworkEditor::initializeSubnet(const QString& name, const ModuleId& mid, NetworkEditor* subnet)
{
  subnet->parentNetwork_ = this;
  subnet->setNetworkEditorController(getNetworkEditorController());

  subnet->setSceneRect(QRectF(0, 0, 400, 400));

  for (auto& item : childrenNetworkItems_[name])
  {
    subnet->scene_->addItem(item);
    item->setVisible(true);
    item->ensureVisible();
  }

  auto dock = new SubnetworkEditor(subnet, mid, name, parentWidget());
  dock->show();

  childrenNetworks_[name] = dock;
}

class SubnetModule : public Module
{
public:
  SubnetModule(const std::vector<ModuleHandle>& underlyingModules, const QList<QGraphicsItem*>& items) : Module(ModuleLookupInfo()),
    underlyingModules_(underlyingModules), items_(items)
  {
    set_id("Subnet:" + boost::lexical_cast<std::string>(subnetCount_));
    subnetCount_++;
  }
  virtual void execute() override
  {
    //std::ostringstream ostr;
    //ostr << "Module " << get_module_name() << " executing for " << 3.14 << " seconds." << std::endl;
    //status(ostr.str());
  }

  static const AlgorithmParameterName ModuleInfo;

  virtual void setStateDefaults() override
  {
    auto state = get_state();

    auto table = makeHomogeneousVariableList(
      [this](size_t i)
      {
        return makeAnonymousVariableList(underlyingModules_[i]->get_id().id_,
          std::string("Push me"),
          boost::lexical_cast<std::string>(underlyingModules_[i]->num_input_ports()),
          boost::lexical_cast<std::string>(underlyingModules_[i]->num_output_ports()));
      },
      underlyingModules_.size());

    state->setValue(ModuleInfo, table);
  }
  std::string listComponentIds() const
  {
    std::ostringstream ostr;
    std::transform(underlyingModules_.begin(), underlyingModules_.end(),
      std::ostream_iterator<std::string>(ostr, ", "),
      [](const ModuleHandle& mod) { return mod->get_id(); });
    return ostr.str();
  }
private:
  std::vector<ModuleHandle> underlyingModules_;
  QList<QGraphicsItem*> items_;
  static int subnetCount_;
};

int SubnetModule::subnetCount_(0);
const AlgorithmParameterName SubnetModule::ModuleInfo("ModuleInfo");

QList<QGraphicsItem*> NetworkEditor::includeConnections(QList<QGraphicsItem*> items) const
{
  QSet<QGraphicsItem*> subnetItems = items.toSet();
  Q_FOREACH(QGraphicsItem* item, items)
  {
    auto module = getModule(item);
    if (module)
    {
      subnetItems.unite(module->connections().toSet());
    }
  }
  return subnetItems.toList();
}

void NetworkEditor::makeSubnetwork()
{
  QRectF rect;
  QPointF position;

  std::vector<ModuleHandle> underlyingModules;
  auto items = scene_->selectedItems();
  Q_FOREACH(QGraphicsItem* item, items)
  {
    auto r = item->boundingRect();
    position = item->pos();
    r = item->mapRectToParent(r);

    if (rect.isEmpty())
      rect = r;
    else
      rect = rect.united(r);

    auto module = getModule(item);
    if (module)
    {
      underlyingModules.push_back(module->getModule());
    }
  }

  if (underlyingModules.empty())
  {
    QMessageBox::information(this, "Make subnetwork", "Please select at least one module.");
    return;
  }

  bool ok;
  auto name = QInputDialog::getText(nullptr, "Make subnet", "Enter subnet name:", QLineEdit::Normal, "subnet", &ok);
  if (!ok || name.isEmpty())
  {
    QMessageBox::information(this, "Make subnetwork", "Invalid name.");
    return;
  }

  makeSubnetworkFromComponents(name, underlyingModules, includeConnections(items), rect);
}

void NetworkEditor::makeSubnetworkFromComponents(const QString& name, const std::vector<ModuleHandle>& modules, QList<QGraphicsItem*> items, const QRectF& rect)
{
  auto subnetModule = boost::make_shared<SubnetModule>(modules, items);
  subnetModule->setStateDefaults();
  subnetModule->get_state()->setValue(Name("Name"), name.toStdString());
  auto moduleWidget = new SubnetWidget(this, name, subnetModule, dialogErrorControl_);

  auto proxy = setupModuleWidget(moduleWidget);

  //TODO: file loading case, duplicated
  moduleWidget->postLoadAction();
  proxy->setScale(1.6);
  auto pic = grabSubnetPic(rect);
  auto tooltipPic = convertToTooltip(pic);
  proxy->setToolTip(tooltipPic);

  auto size = proxy->getModuleWidget()->size();
  if (!rect.isEmpty())
  {
    auto pos = rect.center();
    pos.rx() -= size.width() / 2;
    pos.ry() -= size.height() / 2;
    proxy->setPos(pos);
  }
  else
  {
    //qDebug() << "rect is empty, pos is" << proxy->pos();
  }

  childrenNetworkItems_[name] = items;

  addSubnetChild(name, subnetModule->get_id());
}

QPixmap NetworkEditor::grabSubnetPic(const QRectF& rect)
{
  Q_FOREACH(QGraphicsItem* item, scene_->items())
  {
    if (dynamic_cast<QGraphicsPixmapItem*>(item))
      item->setVisible(false);
  }

  auto pic = QPixmap::grabWidget(this, mapFromScene(rect).boundingRect());

  Q_FOREACH(QGraphicsItem* item, scene_->items())
  {
    if (dynamic_cast<QGraphicsPixmapItem*>(item))
      item->setVisible(true);
  }

  return pic;
}

QString NetworkEditor::convertToTooltip(const QPixmap& pic) const
{
  QByteArray byteArray;
  QBuffer buffer(&byteArray);
  pic.scaled(pic.size() * 0.5).save(&buffer, "PNG");
  return QString("";
}

void NetworkEditor::dumpSubnetworksImpl(const QString& name, Subnetworks& data, ModuleFilter modFilter) const
{
  Q_FOREACH(QGraphicsItem* item, scene_->items())
  {
    if (auto mod = dynamic_cast<ModuleProxyWidget*>(item))
    {
      if (parentNetwork_ && modFilter(mod->getModuleWidget()->getModule()))
      {
        data.subnets[name.toStdString()].push_back(mod->getModuleWidget()->getModuleId());
      }
    }
  }
}

void NetworkEditor::updateSubnetworks(const Subnetworks& subnets)
{
  for (const auto& sub : subnets.subnets)
  {
    std::vector<ModuleHandle> underlying;
    QList<QGraphicsItem*> items;

    Q_FOREACH(QGraphicsItem* item, scene_->items())
    {
      if (auto w = dynamic_cast<ModuleProxyWidget*>(item))
      {
        if (std::find(sub.second.begin(), sub.second.end(), w->getModuleWidget()->getModuleId()) != sub.second.end())
        {
          underlying.push_back(w->getModuleWidget()->getModule());
          items.append(w);
        }
      }
    }
    makeSubnetworkFromComponents(QString::fromStdString(sub.first), underlying, includeConnections(items), {});
  }
}

SubnetWidget::SubnetWidget(NetworkEditor* ed, const QString& name, ModuleHandle theModule, boost::shared_ptr<DialogErrorControl> dialogErrorControl,
  QWidget* parent /* = 0 */) : ModuleWidget(ed, name, theModule, dialogErrorControl, parent), editor_(ed), name_(name)
{
}

SubnetWidget::~SubnetWidget()
{
  editor_->killChild(name_);
}

void NetworkEditor::killChild(const QString& name)
{
  auto subnetIter = childrenNetworks_.find(name);
  if (subnetIter != childrenNetworks_.end())
  {
    subnetIter->second->get()->clear();
    delete subnetIter->second;
    childrenNetworks_.erase(subnetIter);
  }
}<commit_msg>Fix deleting<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2015 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <sstream>
#include <QtGui>
#include <Interface/Application/NetworkEditor.h>
#include <Interface/Application/Node.h>
#include <Interface/Application/Connection.h>
#include <Interface/Application/ModuleWidget.h>
#include <Interface/Application/ModuleProxyWidget.h>
#include <Interface/Application/PortWidgetManager.h>
#include <Interface/Application/NetworkEditorControllerGuiProxy.h>
#include <Interface/Application/Subnetworks.h>
#include <Dataflow/Serialization/Network/NetworkDescriptionSerialization.h>
#include <Dataflow/Engine/Controller/NetworkEditorController.h> //TODO: remove
#include <Dataflow/Network/Module.h> //TODO: remove
#include <Core/Application/Preferences/Preferences.h>
#include <Core/Application/Application.h>
#include <Dataflow/Serialization/Network/XMLSerializer.h>
#include <boost/lambda/lambda.hpp>

using namespace SCIRun;
using namespace SCIRun::Core;
using namespace SCIRun::Core::Algorithms;
using namespace SCIRun::Gui;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Dataflow::Engine;

NetworkEditor::~NetworkEditor()
{
  sendItemsToParent();

  for (auto& child : childrenNetworks_)
  {
    delete child.second->get();
    child.second = nullptr;
  }

  Q_FOREACH(QGraphicsItem* item, scene_->items())
  {
    auto module = getModule(item);
    if (module)
      module->setDeletedFromGui(false);
  }
  NetworkEditor::clear();
}

SubnetworkEditor::SubnetworkEditor(NetworkEditor* editor, const ModuleId& subnetModuleId, const QString& name, QWidget* parent) : QDockWidget(parent),
editor_(editor), name_(name), subnetModuleId_(subnetModuleId)
{
  setupUi(this);
  groupBox->setTitle(name);
  auto vbox = new QVBoxLayout;
  vbox->addWidget(editor);
  groupBox->setLayout(vbox);
  connect(expandPushButton_, SIGNAL(clicked()), this, SLOT(expand()));
  editor_->setParent(groupBox);
}

void SubnetworkEditor::expand()
{
  editor_->sendItemsToParent();
  editor_->parentNetwork()->removeModuleWidget(subnetModuleId_);
}

void NetworkEditor::sendItemsToParent()
{
  if (parentNetwork_)
  {
    for (auto& item : scene_->items())
      parentNetwork_->scene_->addItem(item);
  }
}

void NetworkEditor::removeSubnetChild(const QString& name)
{
  childrenNetworks_.erase(name);
}

void NetworkEditor::addSubnetChild(const QString& name, const ModuleId& mid)
{
  auto it = childrenNetworks_.find(name);
  if (it == childrenNetworks_.end())
  {
    auto subnet = new NetworkEditor(ctorParams_);
    initializeSubnet(name, mid, subnet);
  }
  else
  {
    it->second->show();
  }
}

void NetworkEditor::showSubnetChild(const QString& name)
{
  auto it = childrenNetworks_.find(name);
  if (it == childrenNetworks_.end())
  {
    throw "logical error";
  }
  else
  {
    it->second->show();
  }
}

void NetworkEditor::initializeSubnet(const QString& name, const ModuleId& mid, NetworkEditor* subnet)
{
  subnet->parentNetwork_ = this;
  subnet->setNetworkEditorController(getNetworkEditorController());

  subnet->setSceneRect(QRectF(0, 0, 400, 400));

  for (auto& item : childrenNetworkItems_[name])
  {
    subnet->scene_->addItem(item);
    item->setVisible(true);
    item->ensureVisible();
  }

  auto dock = new SubnetworkEditor(subnet, mid, name, parentWidget());
  dock->show();

  childrenNetworks_[name] = dock;
}

class SubnetModule : public Module
{
public:
  SubnetModule(const std::vector<ModuleHandle>& underlyingModules, const QList<QGraphicsItem*>& items) : Module(ModuleLookupInfo()),
    underlyingModules_(underlyingModules), items_(items)
  {
    set_id("Subnet:" + boost::lexical_cast<std::string>(subnetCount_));
    subnetCount_++;
  }
  virtual void execute() override
  {
    //std::ostringstream ostr;
    //ostr << "Module " << get_module_name() << " executing for " << 3.14 << " seconds." << std::endl;
    //status(ostr.str());
  }

  static const AlgorithmParameterName ModuleInfo;

  virtual void setStateDefaults() override
  {
    auto state = get_state();

    auto table = makeHomogeneousVariableList(
      [this](size_t i)
      {
        return makeAnonymousVariableList(underlyingModules_[i]->get_id().id_,
          std::string("Push me"),
          boost::lexical_cast<std::string>(underlyingModules_[i]->num_input_ports()),
          boost::lexical_cast<std::string>(underlyingModules_[i]->num_output_ports()));
      },
      underlyingModules_.size());

    state->setValue(ModuleInfo, table);
  }
  std::string listComponentIds() const
  {
    std::ostringstream ostr;
    std::transform(underlyingModules_.begin(), underlyingModules_.end(),
      std::ostream_iterator<std::string>(ostr, ", "),
      [](const ModuleHandle& mod) { return mod->get_id(); });
    return ostr.str();
  }
private:
  std::vector<ModuleHandle> underlyingModules_;
  QList<QGraphicsItem*> items_;
  static int subnetCount_;
};

int SubnetModule::subnetCount_(0);
const AlgorithmParameterName SubnetModule::ModuleInfo("ModuleInfo");

QList<QGraphicsItem*> NetworkEditor::includeConnections(QList<QGraphicsItem*> items) const
{
  QSet<QGraphicsItem*> subnetItems = items.toSet();
  Q_FOREACH(QGraphicsItem* item, items)
  {
    auto module = getModule(item);
    if (module)
    {
      subnetItems.unite(module->connections().toSet());
    }
  }
  return subnetItems.toList();
}

void NetworkEditor::makeSubnetwork()
{
  QRectF rect;
  QPointF position;

  std::vector<ModuleHandle> underlyingModules;
  auto items = scene_->selectedItems();
  Q_FOREACH(QGraphicsItem* item, items)
  {
    auto r = item->boundingRect();
    position = item->pos();
    r = item->mapRectToParent(r);

    if (rect.isEmpty())
      rect = r;
    else
      rect = rect.united(r);

    auto module = getModule(item);
    if (module)
    {
      underlyingModules.push_back(module->getModule());
    }
  }

  if (underlyingModules.empty())
  {
    QMessageBox::information(this, "Make subnetwork", "Please select at least one module.");
    return;
  }

  bool ok;
  auto name = QInputDialog::getText(nullptr, "Make subnet", "Enter subnet name:", QLineEdit::Normal, "subnet", &ok);
  if (!ok || name.isEmpty())
  {
    QMessageBox::information(this, "Make subnetwork", "Invalid name.");
    return;
  }

  makeSubnetworkFromComponents(name, underlyingModules, includeConnections(items), rect);
}

void NetworkEditor::makeSubnetworkFromComponents(const QString& name, const std::vector<ModuleHandle>& modules, QList<QGraphicsItem*> items, const QRectF& rect)
{
  auto subnetModule = boost::make_shared<SubnetModule>(modules, items);
  subnetModule->setStateDefaults();
  subnetModule->get_state()->setValue(Name("Name"), name.toStdString());
  auto moduleWidget = new SubnetWidget(this, name, subnetModule, dialogErrorControl_);

  auto proxy = setupModuleWidget(moduleWidget);

  //TODO: file loading case, duplicated
  moduleWidget->postLoadAction();
  proxy->setScale(1.6);
  auto pic = grabSubnetPic(rect);
  auto tooltipPic = convertToTooltip(pic);
  proxy->setToolTip(tooltipPic);

  auto size = proxy->getModuleWidget()->size();
  if (!rect.isEmpty())
  {
    auto pos = rect.center();
    pos.rx() -= size.width() / 2;
    pos.ry() -= size.height() / 2;
    proxy->setPos(pos);
  }
  else
  {
    //qDebug() << "rect is empty, pos is" << proxy->pos();
  }

  childrenNetworkItems_[name] = items;

  addSubnetChild(name, subnetModule->get_id());
}

QPixmap NetworkEditor::grabSubnetPic(const QRectF& rect)
{
  Q_FOREACH(QGraphicsItem* item, scene_->items())
  {
    if (dynamic_cast<QGraphicsPixmapItem*>(item))
      item->setVisible(false);
  }

  auto pic = QPixmap::grabWidget(this, mapFromScene(rect).boundingRect());

  Q_FOREACH(QGraphicsItem* item, scene_->items())
  {
    if (dynamic_cast<QGraphicsPixmapItem*>(item))
      item->setVisible(true);
  }

  return pic;
}

QString NetworkEditor::convertToTooltip(const QPixmap& pic) const
{
  QByteArray byteArray;
  QBuffer buffer(&byteArray);
  pic.scaled(pic.size() * 0.5).save(&buffer, "PNG");
  return QString("";
}

void NetworkEditor::dumpSubnetworksImpl(const QString& name, Subnetworks& data, ModuleFilter modFilter) const
{
  Q_FOREACH(QGraphicsItem* item, scene_->items())
  {
    if (auto mod = dynamic_cast<ModuleProxyWidget*>(item))
    {
      if (parentNetwork_ && modFilter(mod->getModuleWidget()->getModule()))
      {
        data.subnets[name.toStdString()].push_back(mod->getModuleWidget()->getModuleId());
      }
    }
  }
}

void NetworkEditor::updateSubnetworks(const Subnetworks& subnets)
{
  for (const auto& sub : subnets.subnets)
  {
    std::vector<ModuleHandle> underlying;
    QList<QGraphicsItem*> items;

    Q_FOREACH(QGraphicsItem* item, scene_->items())
    {
      if (auto w = dynamic_cast<ModuleProxyWidget*>(item))
      {
        if (std::find(sub.second.begin(), sub.second.end(), w->getModuleWidget()->getModuleId()) != sub.second.end())
        {
          underlying.push_back(w->getModuleWidget()->getModule());
          items.append(w);
        }
      }
    }
    makeSubnetworkFromComponents(QString::fromStdString(sub.first), underlying, includeConnections(items), {});
  }
}

SubnetWidget::SubnetWidget(NetworkEditor* ed, const QString& name, ModuleHandle theModule, boost::shared_ptr<DialogErrorControl> dialogErrorControl,
  QWidget* parent /* = 0 */) : ModuleWidget(ed, name, theModule, dialogErrorControl, parent), editor_(ed), name_(name)
{
}

SubnetWidget::~SubnetWidget()
{
  editor_->killChild(name_);
}

void NetworkEditor::killChild(const QString& name)
{
  auto subnetIter = childrenNetworks_.find(name);
  if (subnetIter != childrenNetworks_.end())
  {
    subnetIter->second->get()->clear();
    delete subnetIter->second;
    childrenNetworks_.erase(subnetIter);
  }
}<|endoftext|>


<commit_before>// Fill out your copyright notice in the Description page of Project Settings.

#include "CLNR.h"
#include "CLNRGameModeBase.h"
#include "Cleaner.h"

void ACLNRGameModeBase::ChangePower(float Value)
{
	if ((CurrentPower - Value) <= 0)
	{
		UE_LOG(LogTemp, Warning, TEXT("No Power left!"));
<<<<<<< HEAD
		UGameplayStatics::OpenLevel(GetWorld(), FName("AudunMap"));
		return;
=======
		UGameplayStatics::OpenLevel(GetWorld(), FName("CafeLevelTest"));
>>>>>>> origin/HansChristianBranch
	}
	CurrentPower -= Value;
	UE_LOG(LogTemp, Warning, TEXT("Power is set to %f"), CurrentPower);

}

<commit_msg>Fixed Conflicts<commit_after>// Fill out your copyright notice in the Description page of Project Settings.

#include "CLNR.h"
#include "CLNRGameModeBase.h"
#include "Cleaner.h"

void ACLNRGameModeBase::ChangePower(float Value)
{
	if ((CurrentPower - Value) <= 0)
	{
		UE_LOG(LogTemp, Warning, TEXT("No Power left!"));
		UGameplayStatics::OpenLevel(GetWorld(), FName("CafeLevelTest"));
		return;

	}
	CurrentPower -= Value;
	UE_LOG(LogTemp, Warning, TEXT("Power is set to %f"), CurrentPower);

}

<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.net>        *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <Standard_Failure.hxx>
#endif

#include <Base/Parameter.h>
#include <App/Application.h>
#include <App/FeaturePythonPyImp.h>
#include <Mod/Part/App/modelRefine.h>
#include "FeatureAddSub.h"
#include "FeaturePy.h"

using namespace PartDesign;

namespace PartDesign {

PROPERTY_SOURCE(PartDesign::FeatureAddSub, PartDesign::Feature)

FeatureAddSub::FeatureAddSub()
  :  addSubType(Additive)
{
    ADD_PROPERTY(AddSubShape,(TopoDS_Shape()));
    ADD_PROPERTY_TYPE(Refine,(0),"Part Design",(App::PropertyType)(App::Prop_None),"Refine shape (clean up redundant edges) after adding/subtracting");
    //init Refine property
    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
        .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/PartDesign");
    this->Refine.setValue(hGrp->GetBool("RefineModel", false));
}

FeatureAddSub::Type FeatureAddSub::getAddSubType()
{
    return addSubType;
}

short FeatureAddSub::mustExecute() const
{
    if (Refine.isTouched())
        return 1;
    return PartDesign::Feature::mustExecute();
}

TopoDS_Shape FeatureAddSub::refineShapeIfActive(const TopoDS_Shape& oldShape) const
{
    if (this->Refine.getValue()) {
        try {
            Part::BRepBuilderAPI_RefineModel mkRefine(oldShape);
            TopoDS_Shape resShape = mkRefine.Shape();
            return resShape;
        }
        catch (Standard_Failure&) {
            return oldShape;
        }
    }

    return oldShape;
}

void FeatureAddSub::getAddSubShape(Part::TopoShape &addShape, Part::TopoShape &subShape)
{
    if (addSubType == Additive)
        addShape = AddSubShape.getShape();
    else if (addSubType == Subtractive)
        subShape = AddSubShape.getShape();
}

}

namespace App {
/// @cond DOXERR
PROPERTY_SOURCE_TEMPLATE(PartDesign::FeatureAddSubPython, PartDesign::FeatureAddSub)
template<> const char* PartDesign::FeatureAddSubPython::getViewProviderName(void) const {
    return "PartDesignGui::ViewProviderPython";
}
template<> PyObject* PartDesign::FeatureAddSubPython::getPyObject(void) {
    if (PythonObject.is(Py::_None())) {
        // ref counter is set to 1
        PythonObject = Py::Object(new FeaturePythonPyT<PartDesign::FeaturePy>(this),true);
    }
    return Py::new_reference_to(PythonObject);
}
/// @endcond

// explicit template instantiation
template class PartDesignExport FeaturePythonT<PartDesign::FeatureAddSub>;
}

namespace PartDesign {

PROPERTY_SOURCE(PartDesign::FeatureAdditivePython, PartDesign::FeatureAddSubPython)

FeatureAdditivePython::FeatureAdditivePython()
{
    addSubType = Additive;
}

FeatureAdditivePython::~FeatureAdditivePython()
{
}

PROPERTY_SOURCE(PartDesign::FeatureSubtractivePython, PartDesign::FeatureAddSubPython)

FeatureSubtractivePython::FeatureSubtractivePython()
{
    addSubType = Subtractive;
}

FeatureSubtractivePython::~FeatureSubtractivePython()
{
}

}
<commit_msg>PartDesign: Check closedness in AddSub refine function<commit_after>/***************************************************************************
 *   Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.net>        *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <Standard_Failure.hxx>
#endif

#include <Base/Parameter.h>
#include <App/Application.h>
#include <App/FeaturePythonPyImp.h>
#include <Mod/Part/App/modelRefine.h>
#include "FeatureAddSub.h"
#include "FeaturePy.h"

using namespace PartDesign;

namespace PartDesign {

PROPERTY_SOURCE(PartDesign::FeatureAddSub, PartDesign::Feature)

FeatureAddSub::FeatureAddSub()
  :  addSubType(Additive)
{
    ADD_PROPERTY(AddSubShape,(TopoDS_Shape()));
    ADD_PROPERTY_TYPE(Refine,(0),"Part Design",(App::PropertyType)(App::Prop_None),"Refine shape (clean up redundant edges) after adding/subtracting");
    //init Refine property
    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
        .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/PartDesign");
    this->Refine.setValue(hGrp->GetBool("RefineModel", false));
}

FeatureAddSub::Type FeatureAddSub::getAddSubType()
{
    return addSubType;
}

short FeatureAddSub::mustExecute() const
{
    if (Refine.isTouched())
        return 1;
    return PartDesign::Feature::mustExecute();
}

TopoDS_Shape FeatureAddSub::refineShapeIfActive(const TopoDS_Shape& oldShape) const
{
    if (this->Refine.getValue()) {
        try {
            Part::BRepBuilderAPI_RefineModel mkRefine(oldShape);
            TopoDS_Shape resShape = mkRefine.Shape();
            if (!TopoShape(resShape).isClosed()) {
                return oldShape;
            }
            return resShape;
        }
        catch (Standard_Failure&) {
            return oldShape;
        }
    }

    return oldShape;
}

void FeatureAddSub::getAddSubShape(Part::TopoShape &addShape, Part::TopoShape &subShape)
{
    if (addSubType == Additive)
        addShape = AddSubShape.getShape();
    else if (addSubType == Subtractive)
        subShape = AddSubShape.getShape();
}

}

namespace App {
/// @cond DOXERR
PROPERTY_SOURCE_TEMPLATE(PartDesign::FeatureAddSubPython, PartDesign::FeatureAddSub)
template<> const char* PartDesign::FeatureAddSubPython::getViewProviderName(void) const {
    return "PartDesignGui::ViewProviderPython";
}
template<> PyObject* PartDesign::FeatureAddSubPython::getPyObject(void) {
    if (PythonObject.is(Py::_None())) {
        // ref counter is set to 1
        PythonObject = Py::Object(new FeaturePythonPyT<PartDesign::FeaturePy>(this),true);
    }
    return Py::new_reference_to(PythonObject);
}
/// @endcond

// explicit template instantiation
template class PartDesignExport FeaturePythonT<PartDesign::FeatureAddSub>;
}

namespace PartDesign {

PROPERTY_SOURCE(PartDesign::FeatureAdditivePython, PartDesign::FeatureAddSubPython)

FeatureAdditivePython::FeatureAdditivePython()
{
    addSubType = Additive;
}

FeatureAdditivePython::~FeatureAdditivePython()
{
}

PROPERTY_SOURCE(PartDesign::FeatureSubtractivePython, PartDesign::FeatureAddSubPython)

FeatureSubtractivePython::FeatureSubtractivePython()
{
    addSubType = Subtractive;
}

FeatureSubtractivePython::~FeatureSubtractivePython()
{
}

}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <BRepFilletAPI_MakeFillet.hxx>
# include <TopExp_Explorer.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Edge.hxx>
#endif

#include <Base/Console.h>
#include <Base/Reader.h>
#include <Mod/Part/App/TopoShape.h>

#include "FeatureFillet.h"

using namespace PartDesign;

PROPERTY_SOURCE(PartDesign::Fillet, PartDesign::DressUp)

const App::PropertyQuantityConstraint::Constraints floatRadius = {0.0,FLT_MAX,0.1};

Fillet::Fillet()
{
    ADD_PROPERTY(Radius,(1.0));
    Radius.setUnit(Base::Unit::Length);
    Radius.setConstraints(&floatRadius);
}

short Fillet::mustExecute() const
{
    if (Placement.isTouched() || Radius.isTouched())
        return 1;
    return DressUp::mustExecute();
}

App::DocumentObjectExecReturn *Fillet::execute(void)
{
    App::DocumentObject* link = Base.getValue();
    if (!link)
        return new App::DocumentObjectExecReturn("No object linked");
    if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
        return new App::DocumentObjectExecReturn("Linked object is not a Part object");
    Part::Feature *base = static_cast<Part::Feature*>(Base.getValue());
    const Part::TopoShape& TopShape = base->Shape.getShape();
    if (TopShape._Shape.IsNull())
        return new App::DocumentObjectExecReturn("Cannot fillet invalid shape");

    const std::vector<std::string>& SubVals = Base.getSubValuesStartsWith("Edge");
    if (SubVals.size() == 0)
        return new App::DocumentObjectExecReturn("No edges specified");

    double radius = Radius.getValue();

    this->positionByBase();
    // create an untransformed copy of the base shape
    Part::TopoShape baseShape(TopShape);
    baseShape.setTransform(Base::Matrix4D());
    try {
        BRepFilletAPI_MakeFillet mkFillet(baseShape._Shape);

        for (std::vector<std::string>::const_iterator it=SubVals.begin(); it != SubVals.end(); ++it) {
            TopoDS_Edge edge = TopoDS::Edge(baseShape.getSubShape(it->c_str()));
            mkFillet.Add(radius, edge);
        }

        mkFillet.Build();
        if (!mkFillet.IsDone())
            return new App::DocumentObjectExecReturn("Failed to create fillet");

        TopoDS_Shape shape = mkFillet.Shape();
        if (shape.IsNull())
            return new App::DocumentObjectExecReturn("Resulting shape is null");

        this->Shape.setValue(shape);
        return App::DocumentObject::StdReturn;
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        return new App::DocumentObjectExecReturn(e->GetMessageString());
    }
}

void Fillet::Restore(Base::XMLReader &reader)
{
    reader.readElement("Properties");
    int Cnt = reader.getAttributeAsInteger("Count");

    for (int i=0 ;i<Cnt ;i++) {
        reader.readElement("Property");
        const char* PropName = reader.getAttribute("name");
        const char* TypeName = reader.getAttribute("type");
        App::Property* prop = getPropertyByName(PropName);

        try {
            if (prop && strcmp(prop->getTypeId().getName(), TypeName) == 0) {
                prop->Restore(reader);
            }
            else if (prop && strcmp(TypeName,"App::PropertyFloatConstraint") == 0 &&
                     strcmp(prop->getTypeId().getName(), "App::PropertyQuantityConstraint") == 0) {
                App::PropertyFloatConstraint p;
                p.Restore(reader);
                static_cast<App::PropertyQuantityConstraint*>(prop)->setValue(p.getValue());
            }
        }
        catch (const Base::XMLParseException&) {
            throw; // re-throw
        }
        catch (const Base::Exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        catch (const std::exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        reader.readEndElement("Property");
    }
    reader.readEndElement("Properties");
}
<commit_msg>+ add extra check if fillet operation returns valid shape<commit_after>/***************************************************************************
 *   Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <BRepAlgo.hxx>
# include <BRepFilletAPI_MakeFillet.hxx>
# include <TopExp_Explorer.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Edge.hxx>
# include <TopTools_ListOfShape.hxx>
#endif

#include <Base/Console.h>
#include <Base/Reader.h>
#include <Mod/Part/App/TopoShape.h>

#include "FeatureFillet.h"

using namespace PartDesign;

PROPERTY_SOURCE(PartDesign::Fillet, PartDesign::DressUp)

const App::PropertyQuantityConstraint::Constraints floatRadius = {0.0,FLT_MAX,0.1};

Fillet::Fillet()
{
    ADD_PROPERTY(Radius,(1.0));
    Radius.setUnit(Base::Unit::Length);
    Radius.setConstraints(&floatRadius);
}

short Fillet::mustExecute() const
{
    if (Placement.isTouched() || Radius.isTouched())
        return 1;
    return DressUp::mustExecute();
}

App::DocumentObjectExecReturn *Fillet::execute(void)
{
    App::DocumentObject* link = Base.getValue();
    if (!link)
        return new App::DocumentObjectExecReturn("No object linked");
    if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
        return new App::DocumentObjectExecReturn("Linked object is not a Part object");
    Part::Feature *base = static_cast<Part::Feature*>(Base.getValue());
    const Part::TopoShape& TopShape = base->Shape.getShape();
    if (TopShape._Shape.IsNull())
        return new App::DocumentObjectExecReturn("Cannot fillet invalid shape");

    const std::vector<std::string>& SubVals = Base.getSubValuesStartsWith("Edge");
    if (SubVals.size() == 0)
        return new App::DocumentObjectExecReturn("No edges specified");

    double radius = Radius.getValue();

    this->positionByBase();
    // create an untransformed copy of the base shape
    Part::TopoShape baseShape(TopShape);
    baseShape.setTransform(Base::Matrix4D());
    try {
        BRepFilletAPI_MakeFillet mkFillet(baseShape._Shape);

        for (std::vector<std::string>::const_iterator it=SubVals.begin(); it != SubVals.end(); ++it) {
            TopoDS_Edge edge = TopoDS::Edge(baseShape.getSubShape(it->c_str()));
            mkFillet.Add(radius, edge);
        }

        mkFillet.Build();
        if (!mkFillet.IsDone())
            return new App::DocumentObjectExecReturn("Failed to create fillet");

        TopoDS_Shape shape = mkFillet.Shape();
        if (shape.IsNull())
            return new App::DocumentObjectExecReturn("Resulting shape is null");

        TopTools_ListOfShape aLarg;
        aLarg.Append(baseShape._Shape);
        if (!BRepAlgo::IsValid(aLarg, shape, Standard_False, Standard_False)) {
            return new App::DocumentObjectExecReturn("Resulting shape is invalid");
        }

        this->Shape.setValue(shape);
        return App::DocumentObject::StdReturn;
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        return new App::DocumentObjectExecReturn(e->GetMessageString());
    }
}

void Fillet::Restore(Base::XMLReader &reader)
{
    reader.readElement("Properties");
    int Cnt = reader.getAttributeAsInteger("Count");

    for (int i=0 ;i<Cnt ;i++) {
        reader.readElement("Property");
        const char* PropName = reader.getAttribute("name");
        const char* TypeName = reader.getAttribute("type");
        App::Property* prop = getPropertyByName(PropName);

        try {
            if (prop && strcmp(prop->getTypeId().getName(), TypeName) == 0) {
                prop->Restore(reader);
            }
            else if (prop && strcmp(TypeName,"App::PropertyFloatConstraint") == 0 &&
                     strcmp(prop->getTypeId().getName(), "App::PropertyQuantityConstraint") == 0) {
                App::PropertyFloatConstraint p;
                p.Restore(reader);
                static_cast<App::PropertyQuantityConstraint*>(prop)->setValue(p.getValue());
            }
        }
        catch (const Base::XMLParseException&) {
            throw; // re-throw
        }
        catch (const Base::Exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        catch (const std::exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        reader.readEndElement("Property");
    }
    reader.readEndElement("Properties");
}
<|endoftext|>